exfldio.c revision 210976
167754Smsmith/****************************************************************************** 267754Smsmith * 377424Smsmith * Module Name: exfldio - Aml Field I/O 467754Smsmith * 567754Smsmith *****************************************************************************/ 667754Smsmith 767754Smsmith/****************************************************************************** 867754Smsmith * 967754Smsmith * 1. Copyright Notice 1067754Smsmith * 11202771Sjkim * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp. 1270243Smsmith * All rights reserved. 1367754Smsmith * 1467754Smsmith * 2. License 1567754Smsmith * 1667754Smsmith * 2.1. This is your license from Intel Corp. under its intellectual property 1767754Smsmith * rights. You may have additional license terms from the party that provided 1867754Smsmith * you this software, covering your right to use that party's intellectual 1967754Smsmith * property rights. 2067754Smsmith * 2167754Smsmith * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 2267754Smsmith * copy of the source code appearing in this file ("Covered Code") an 2367754Smsmith * irrevocable, perpetual, worldwide license under Intel's copyrights in the 2467754Smsmith * base code distributed originally by Intel ("Original Intel Code") to copy, 2567754Smsmith * make derivatives, distribute, use and display any portion of the Covered 2667754Smsmith * Code in any form, with the right to sublicense such rights; and 2767754Smsmith * 2867754Smsmith * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 2967754Smsmith * license (with the right to sublicense), under only those claims of Intel 3067754Smsmith * patents that are infringed by the Original Intel Code, to make, use, sell, 3167754Smsmith * offer to sell, and import the Covered Code and derivative works thereof 3267754Smsmith * solely to the minimum extent necessary to exercise the above copyright 3367754Smsmith * license, and in no event shall the patent license extend to any additions 3467754Smsmith * to or modifications of the Original Intel Code. No other license or right 3567754Smsmith * is granted directly or by implication, estoppel or otherwise; 3667754Smsmith * 3767754Smsmith * The above copyright and patent license is granted only if the following 3867754Smsmith * conditions are met: 3967754Smsmith * 4067754Smsmith * 3. Conditions 4167754Smsmith * 4267754Smsmith * 3.1. Redistribution of Source with Rights to Further Distribute Source. 4367754Smsmith * Redistribution of source code of any substantial portion of the Covered 4467754Smsmith * Code or modification with rights to further distribute source must include 4567754Smsmith * the above Copyright Notice, the above License, this list of Conditions, 4667754Smsmith * and the following Disclaimer and Export Compliance provision. In addition, 4767754Smsmith * Licensee must cause all Covered Code to which Licensee contributes to 4867754Smsmith * contain a file documenting the changes Licensee made to create that Covered 4967754Smsmith * Code and the date of any change. Licensee must include in that file the 5067754Smsmith * documentation of any changes made by any predecessor Licensee. Licensee 5167754Smsmith * must include a prominent statement that the modification is derived, 5267754Smsmith * directly or indirectly, from Original Intel Code. 5367754Smsmith * 5467754Smsmith * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 5567754Smsmith * Redistribution of source code of any substantial portion of the Covered 5667754Smsmith * Code or modification without rights to further distribute source must 5767754Smsmith * include the following Disclaimer and Export Compliance provision in the 5867754Smsmith * documentation and/or other materials provided with distribution. In 5967754Smsmith * addition, Licensee may not authorize further sublicense of source of any 6067754Smsmith * portion of the Covered Code, and must include terms to the effect that the 6167754Smsmith * license from Licensee to its licensee is limited to the intellectual 6267754Smsmith * property embodied in the software Licensee provides to its licensee, and 6367754Smsmith * not to intellectual property embodied in modifications its licensee may 6467754Smsmith * make. 6567754Smsmith * 6667754Smsmith * 3.3. Redistribution of Executable. Redistribution in executable form of any 6767754Smsmith * substantial portion of the Covered Code or modification must reproduce the 6867754Smsmith * above Copyright Notice, and the following Disclaimer and Export Compliance 6967754Smsmith * provision in the documentation and/or other materials provided with the 7067754Smsmith * distribution. 7167754Smsmith * 7267754Smsmith * 3.4. Intel retains all right, title, and interest in and to the Original 7367754Smsmith * Intel Code. 7467754Smsmith * 7567754Smsmith * 3.5. Neither the name Intel nor any other trademark owned or controlled by 7667754Smsmith * Intel shall be used in advertising or otherwise to promote the sale, use or 7767754Smsmith * other dealings in products derived from or relating to the Covered Code 7867754Smsmith * without prior written authorization from Intel. 7967754Smsmith * 8067754Smsmith * 4. Disclaimer and Export Compliance 8167754Smsmith * 8267754Smsmith * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 8367754Smsmith * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 8467754Smsmith * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 8567754Smsmith * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 8667754Smsmith * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 8767754Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 8867754Smsmith * PARTICULAR PURPOSE. 8967754Smsmith * 9067754Smsmith * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 9167754Smsmith * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 9267754Smsmith * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 9367754Smsmith * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 9467754Smsmith * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 9567754Smsmith * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 9667754Smsmith * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 9767754Smsmith * LIMITED REMEDY. 9867754Smsmith * 9967754Smsmith * 4.3. Licensee shall not export, either directly or indirectly, any of this 10067754Smsmith * software or system incorporating such software without first obtaining any 10167754Smsmith * required license or other approval from the U. S. Department of Commerce or 10267754Smsmith * any other agency or department of the United States Government. In the 10367754Smsmith * event Licensee exports any such software from the United States or 10467754Smsmith * re-exports any such software from a foreign destination, Licensee shall 10567754Smsmith * ensure that the distribution and export/re-export of the software is in 10667754Smsmith * compliance with all laws, regulations, orders, or other restrictions of the 10767754Smsmith * U.S. Export Administration Regulations. Licensee agrees that neither it nor 10867754Smsmith * any of its subsidiaries will export/re-export any technical data, process, 10967754Smsmith * software, or service, directly or indirectly, to any country for which the 11067754Smsmith * United States government or any agency thereof requires an export license, 11167754Smsmith * other governmental approval, or letter of assurance, without first obtaining 11267754Smsmith * such license, approval or letter. 11367754Smsmith * 11467754Smsmith *****************************************************************************/ 11567754Smsmith 11667754Smsmith 11777424Smsmith#define __EXFLDIO_C__ 11867754Smsmith 119193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 120193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 121193341Sjkim#include <contrib/dev/acpica/include/acinterp.h> 122193341Sjkim#include <contrib/dev/acpica/include/amlcode.h> 123193341Sjkim#include <contrib/dev/acpica/include/acevents.h> 124193341Sjkim#include <contrib/dev/acpica/include/acdispat.h> 12567754Smsmith 12667754Smsmith 12777424Smsmith#define _COMPONENT ACPI_EXECUTER 12891116Smsmith ACPI_MODULE_NAME ("exfldio") 12967754Smsmith 130151937Sjkim/* Local prototypes */ 13167754Smsmith 132151937Sjkimstatic ACPI_STATUS 133151937SjkimAcpiExFieldDatumIo ( 134151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 135151937Sjkim UINT32 FieldDatumByteOffset, 136202771Sjkim UINT64 *Value, 137151937Sjkim UINT32 ReadWrite); 138151937Sjkim 139151937Sjkimstatic BOOLEAN 140151937SjkimAcpiExRegisterOverflow ( 141151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 142202771Sjkim UINT64 Value); 143151937Sjkim 144151937Sjkimstatic ACPI_STATUS 145151937SjkimAcpiExSetupRegion ( 146151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 147151937Sjkim UINT32 FieldDatumByteOffset); 148151937Sjkim 149151937Sjkim 15067754Smsmith/******************************************************************************* 15167754Smsmith * 15287031Smsmith * FUNCTION: AcpiExSetupRegion 15367754Smsmith * 154151937Sjkim * PARAMETERS: ObjDesc - Field to be read or written 15587031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 15687031Smsmith * parent field 15767754Smsmith * 15867754Smsmith * RETURN: Status 15967754Smsmith * 16077424Smsmith * DESCRIPTION: Common processing for AcpiExExtractFromField and 161123315Snjl * AcpiExInsertIntoField. Initialize the Region if necessary and 162123315Snjl * validate the request. 16367754Smsmith * 16467754Smsmith ******************************************************************************/ 16567754Smsmith 166151937Sjkimstatic ACPI_STATUS 16787031SmsmithAcpiExSetupRegion ( 16867754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 16977424Smsmith UINT32 FieldDatumByteOffset) 17067754Smsmith{ 17177424Smsmith ACPI_STATUS Status = AE_OK; 17277424Smsmith ACPI_OPERAND_OBJECT *RgnDesc; 17367754Smsmith 17467754Smsmith 175167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset); 17667754Smsmith 17783174Smsmith 17877424Smsmith RgnDesc = ObjDesc->CommonField.RegionObj; 17967754Smsmith 180107325Siwasaki /* We must have a valid region */ 181107325Siwasaki 182193267Sjkim if (RgnDesc->Common.Type != ACPI_TYPE_REGION) 18377424Smsmith { 184204773Sjkim ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)", 185193267Sjkim RgnDesc->Common.Type, 18699679Siwasaki AcpiUtGetObjectTypeName (RgnDesc))); 18799679Siwasaki 18877424Smsmith return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 18977424Smsmith } 19067754Smsmith 19177424Smsmith /* 19277424Smsmith * If the Region Address and Length have not been previously evaluated, 19377424Smsmith * evaluate them now and save the results. 19477424Smsmith */ 195123315Snjl if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) 19667754Smsmith { 19777424Smsmith Status = AcpiDsGetRegionArguments (RgnDesc); 19877424Smsmith if (ACPI_FAILURE (Status)) 19977424Smsmith { 20077424Smsmith return_ACPI_STATUS (Status); 20177424Smsmith } 20267754Smsmith } 20367754Smsmith 204167802Sjkim /* 205210976Sjkim * Exit now for SMBus or IPMI address space, it has a non-linear 206210976Sjkim * address space and the request cannot be directly validated 207167802Sjkim */ 208197104Sjkim if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 209197104Sjkim RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI) 210107325Siwasaki { 211197104Sjkim /* SMBus or IPMI has a non-linear address space */ 212107325Siwasaki 213107325Siwasaki return_ACPI_STATUS (AE_OK); 214107325Siwasaki } 215107325Siwasaki 216123315Snjl#ifdef ACPI_UNDER_DEVELOPMENT 21777424Smsmith /* 218123315Snjl * If the Field access is AnyAcc, we can now compute the optimal 219123315Snjl * access (because we know know the length of the parent region) 220123315Snjl */ 221123315Snjl if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 222123315Snjl { 223123315Snjl if (ACPI_FAILURE (Status)) 224123315Snjl { 225123315Snjl return_ACPI_STATUS (Status); 226123315Snjl } 227123315Snjl } 228123315Snjl#endif 229123315Snjl 230123315Snjl /* 23177424Smsmith * Validate the request. The entire request from the byte offset for a 23277424Smsmith * length of one field datum (access width) must fit within the region. 23377424Smsmith * (Region length is specified in bytes) 23477424Smsmith */ 235167802Sjkim if (RgnDesc->Region.Length < 236210976Sjkim (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset + 237167802Sjkim ObjDesc->CommonField.AccessByteWidth)) 23877424Smsmith { 239138287Smarks if (AcpiGbl_EnableInterpreterSlack) 240138287Smarks { 241138287Smarks /* 242138287Smarks * Slack mode only: We will go ahead and allow access to this 243138287Smarks * field if it is within the region length rounded up to the next 244193267Sjkim * access width boundary. ACPI_SIZE cast for 64-bit compile. 245138287Smarks */ 246138287Smarks if (ACPI_ROUND_UP (RgnDesc->Region.Length, 247167802Sjkim ObjDesc->CommonField.AccessByteWidth) >= 248193267Sjkim ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset + 249193267Sjkim ObjDesc->CommonField.AccessByteWidth + 250193267Sjkim FieldDatumByteOffset)) 251138287Smarks { 252138287Smarks return_ACPI_STATUS (AE_OK); 253138287Smarks } 254138287Smarks } 255138287Smarks 25677424Smsmith if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth) 25777424Smsmith { 25883174Smsmith /* 25977424Smsmith * This is the case where the AccessType (AccWord, etc.) is wider 26077424Smsmith * than the region itself. For example, a region of length one 26177424Smsmith * byte, and a field with Dword access specified. 26277424Smsmith */ 263167802Sjkim ACPI_ERROR ((AE_INFO, 264204773Sjkim "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)", 265123315Snjl AcpiUtGetNodeName (ObjDesc->CommonField.Node), 266123315Snjl ObjDesc->CommonField.AccessByteWidth, 267151937Sjkim AcpiUtGetNodeName (RgnDesc->Region.Node), 268151937Sjkim RgnDesc->Region.Length)); 26977424Smsmith } 27077424Smsmith 27177424Smsmith /* 27277424Smsmith * Offset rounded up to next multiple of field width 27377424Smsmith * exceeds region length, indicate an error 27477424Smsmith */ 275167802Sjkim ACPI_ERROR ((AE_INFO, 276204773Sjkim "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)", 277123315Snjl AcpiUtGetNodeName (ObjDesc->CommonField.Node), 278123315Snjl ObjDesc->CommonField.BaseByteOffset, 27991116Smsmith FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, 280151937Sjkim AcpiUtGetNodeName (RgnDesc->Region.Node), 281151937Sjkim RgnDesc->Region.Length)); 28277424Smsmith 28377424Smsmith return_ACPI_STATUS (AE_AML_REGION_LIMIT); 28477424Smsmith } 28577424Smsmith 28677424Smsmith return_ACPI_STATUS (AE_OK); 28777424Smsmith} 28877424Smsmith 28977424Smsmith 29077424Smsmith/******************************************************************************* 29177424Smsmith * 29287031Smsmith * FUNCTION: AcpiExAccessRegion 29377424Smsmith * 294151937Sjkim * PARAMETERS: ObjDesc - Field to be read 29587031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 29687031Smsmith * parent field 297151937Sjkim * Value - Where to store value (must at least 298202771Sjkim * 64 bits) 299107325Siwasaki * Function - Read or Write flag plus other region- 300107325Siwasaki * dependent flags 30177424Smsmith * 30277424Smsmith * RETURN: Status 30377424Smsmith * 30487031Smsmith * DESCRIPTION: Read or Write a single field datum to an Operation Region. 30577424Smsmith * 30677424Smsmith ******************************************************************************/ 30777424Smsmith 30877424SmsmithACPI_STATUS 30987031SmsmithAcpiExAccessRegion ( 31077424Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 31177424Smsmith UINT32 FieldDatumByteOffset, 312202771Sjkim UINT64 *Value, 313107325Siwasaki UINT32 Function) 31477424Smsmith{ 31577424Smsmith ACPI_STATUS Status; 31677424Smsmith ACPI_OPERAND_OBJECT *RgnDesc; 317193267Sjkim UINT32 RegionOffset; 31877424Smsmith 31977424Smsmith 320167802Sjkim ACPI_FUNCTION_TRACE (ExAccessRegion); 32177424Smsmith 32277424Smsmith 323114237Snjl /* 324107325Siwasaki * Ensure that the region operands are fully evaluated and verify 325107325Siwasaki * the validity of the request 326107325Siwasaki */ 327107325Siwasaki Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset); 328107325Siwasaki if (ACPI_FAILURE (Status)) 329107325Siwasaki { 330107325Siwasaki return_ACPI_STATUS (Status); 331107325Siwasaki } 332107325Siwasaki 33387031Smsmith /* 33487031Smsmith * The physical address of this field datum is: 33587031Smsmith * 33687031Smsmith * 1) The base of the region, plus 33787031Smsmith * 2) The base offset of the field, plus 33887031Smsmith * 3) The current offset into the field 33987031Smsmith */ 34087031Smsmith RgnDesc = ObjDesc->CommonField.RegionObj; 341193267Sjkim RegionOffset = 342193267Sjkim ObjDesc->CommonField.BaseByteOffset + 343193267Sjkim FieldDatumByteOffset; 34487031Smsmith 345107325Siwasaki if ((Function & ACPI_IO_MASK) == ACPI_READ) 34667754Smsmith { 34787031Smsmith ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); 34867754Smsmith } 34987031Smsmith else 35087031Smsmith { 35187031Smsmith ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); 35287031Smsmith } 35367754Smsmith 35487031Smsmith ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, 355167802Sjkim " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", 35687031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 35787031Smsmith RgnDesc->Region.SpaceId, 35891116Smsmith ObjDesc->CommonField.AccessByteWidth, 35987031Smsmith ObjDesc->CommonField.BaseByteOffset, 36087031Smsmith FieldDatumByteOffset, 361193267Sjkim ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset)))); 36267754Smsmith 36387031Smsmith /* Invoke the appropriate AddressSpace/OpRegion handler */ 36477424Smsmith 365193267Sjkim Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, RegionOffset, 366151937Sjkim ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); 36787031Smsmith 36887031Smsmith if (ACPI_FAILURE (Status)) 36987031Smsmith { 37087031Smsmith if (Status == AE_NOT_IMPLEMENTED) 37187031Smsmith { 372167802Sjkim ACPI_ERROR ((AE_INFO, 373204773Sjkim "Region %s(0x%X) not implemented", 37487031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 37587031Smsmith RgnDesc->Region.SpaceId)); 37687031Smsmith } 37787031Smsmith else if (Status == AE_NOT_EXIST) 37887031Smsmith { 379167802Sjkim ACPI_ERROR ((AE_INFO, 380204773Sjkim "Region %s(0x%X) has no handler", 38187031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 38287031Smsmith RgnDesc->Region.SpaceId)); 38387031Smsmith } 38487031Smsmith } 38587031Smsmith 38687031Smsmith return_ACPI_STATUS (Status); 38787031Smsmith} 38887031Smsmith 38987031Smsmith 39087031Smsmith/******************************************************************************* 39187031Smsmith * 39287031Smsmith * FUNCTION: AcpiExRegisterOverflow 39387031Smsmith * 394151937Sjkim * PARAMETERS: ObjDesc - Register(Field) to be written 39587031Smsmith * Value - Value to be stored 39687031Smsmith * 39787031Smsmith * RETURN: TRUE if value overflows the field, FALSE otherwise 39887031Smsmith * 39987031Smsmith * DESCRIPTION: Check if a value is out of range of the field being written. 40087031Smsmith * Used to check if the values written to Index and Bank registers 40187031Smsmith * are out of range. Normally, the value is simply truncated 40287031Smsmith * to fit the field, but this case is most likely a serious 40387031Smsmith * coding error in the ASL. 40487031Smsmith * 40587031Smsmith ******************************************************************************/ 40687031Smsmith 407151937Sjkimstatic BOOLEAN 40887031SmsmithAcpiExRegisterOverflow ( 40987031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 410202771Sjkim UINT64 Value) 41187031Smsmith{ 41287031Smsmith 41391116Smsmith if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE) 41491116Smsmith { 41591116Smsmith /* 41691116Smsmith * The field is large enough to hold the maximum integer, so we can 41791116Smsmith * never overflow it. 41891116Smsmith */ 41991116Smsmith return (FALSE); 42091116Smsmith } 42191116Smsmith 422202771Sjkim if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength)) 42387031Smsmith { 42491116Smsmith /* 42591116Smsmith * The Value is larger than the maximum value that can fit into 42691116Smsmith * the register. 42791116Smsmith */ 42887031Smsmith return (TRUE); 42987031Smsmith } 43087031Smsmith 43191116Smsmith /* The Value will fit into the field with no truncation */ 43291116Smsmith 43387031Smsmith return (FALSE); 43487031Smsmith} 43587031Smsmith 43687031Smsmith 43787031Smsmith/******************************************************************************* 43887031Smsmith * 43987031Smsmith * FUNCTION: AcpiExFieldDatumIo 44087031Smsmith * 441151937Sjkim * PARAMETERS: ObjDesc - Field to be read 44287031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 44387031Smsmith * parent field 444151937Sjkim * Value - Where to store value (must be 64 bits) 44587031Smsmith * ReadWrite - Read or Write flag 44687031Smsmith * 44787031Smsmith * RETURN: Status 44887031Smsmith * 44987031Smsmith * DESCRIPTION: Read or Write a single datum of a field. The FieldType is 45087031Smsmith * demultiplexed here to handle the different types of fields 45187031Smsmith * (BufferField, RegionField, IndexField, BankField) 45287031Smsmith * 45387031Smsmith ******************************************************************************/ 45487031Smsmith 455151937Sjkimstatic ACPI_STATUS 45687031SmsmithAcpiExFieldDatumIo ( 45787031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 45887031Smsmith UINT32 FieldDatumByteOffset, 459202771Sjkim UINT64 *Value, 46087031Smsmith UINT32 ReadWrite) 46187031Smsmith{ 46287031Smsmith ACPI_STATUS Status; 463202771Sjkim UINT64 LocalValue; 46487031Smsmith 46587031Smsmith 466167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset); 46787031Smsmith 46887031Smsmith 46987031Smsmith if (ReadWrite == ACPI_READ) 47087031Smsmith { 47187031Smsmith if (!Value) 47287031Smsmith { 47387031Smsmith LocalValue = 0; 474151937Sjkim 475151937Sjkim /* To support reads without saving return value */ 476151937Sjkim Value = &LocalValue; 47787031Smsmith } 47887031Smsmith 47987031Smsmith /* Clear the entire return buffer first, [Very Important!] */ 48087031Smsmith 48187031Smsmith *Value = 0; 48287031Smsmith } 48387031Smsmith 48487031Smsmith /* 48587031Smsmith * The four types of fields are: 48687031Smsmith * 487122944Snjl * BufferField - Read/write from/to a Buffer 488122944Snjl * RegionField - Read/write from/to a Operation Region. 489151937Sjkim * BankField - Write to a Bank Register, then read/write from/to an 490151937Sjkim * OperationRegion 491151937Sjkim * IndexField - Write to an Index Register, then read/write from/to a 492151937Sjkim * Data Register 49387031Smsmith */ 494193267Sjkim switch (ObjDesc->Common.Type) 49577424Smsmith { 49677424Smsmith case ACPI_TYPE_BUFFER_FIELD: 49777424Smsmith /* 49887031Smsmith * If the BufferField arguments have not been previously evaluated, 49987031Smsmith * evaluate them now and save the results. 50077424Smsmith */ 50187031Smsmith if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 50287031Smsmith { 50387031Smsmith Status = AcpiDsGetBufferFieldArguments (ObjDesc); 50487031Smsmith if (ACPI_FAILURE (Status)) 50587031Smsmith { 50687031Smsmith return_ACPI_STATUS (Status); 50787031Smsmith } 50887031Smsmith } 50987031Smsmith 51087031Smsmith if (ReadWrite == ACPI_READ) 51187031Smsmith { 51287031Smsmith /* 51387031Smsmith * Copy the data from the source buffer. 51487031Smsmith * Length is the field width in bytes. 51587031Smsmith */ 516151937Sjkim ACPI_MEMCPY (Value, 517151937Sjkim (ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 518151937Sjkim ObjDesc->BufferField.BaseByteOffset + 519151937Sjkim FieldDatumByteOffset, 520151937Sjkim ObjDesc->CommonField.AccessByteWidth); 52187031Smsmith } 52287031Smsmith else 52387031Smsmith { 52487031Smsmith /* 52587031Smsmith * Copy the data to the target buffer. 52687031Smsmith * Length is the field width in bytes. 52787031Smsmith */ 528151937Sjkim ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 529167802Sjkim ObjDesc->BufferField.BaseByteOffset + 530167802Sjkim FieldDatumByteOffset, 531167802Sjkim Value, ObjDesc->CommonField.AccessByteWidth); 53287031Smsmith } 53387031Smsmith 53477424Smsmith Status = AE_OK; 53577424Smsmith break; 53667754Smsmith 53767754Smsmith 538107325Siwasaki case ACPI_TYPE_LOCAL_BANK_FIELD: 53967754Smsmith 540151937Sjkim /* 541151937Sjkim * Ensure that the BankValue is not beyond the capacity of 542151937Sjkim * the register 543151937Sjkim */ 54487031Smsmith if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, 545202771Sjkim (UINT64) ObjDesc->BankField.Value)) 54687031Smsmith { 54787031Smsmith return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 54887031Smsmith } 54987031Smsmith 55077424Smsmith /* 55187031Smsmith * For BankFields, we must write the BankValue to the BankRegister 55287031Smsmith * (itself a RegionField) before we can access the data. 55377424Smsmith */ 55487031Smsmith Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, 555167802Sjkim &ObjDesc->BankField.Value, 556167802Sjkim sizeof (ObjDesc->BankField.Value)); 55777424Smsmith if (ACPI_FAILURE (Status)) 55877424Smsmith { 55977424Smsmith return_ACPI_STATUS (Status); 56077424Smsmith } 56167754Smsmith 56277424Smsmith /* 56387031Smsmith * Now that the Bank has been selected, fall through to the 56487031Smsmith * RegionField case and write the datum to the Operation Region 56577424Smsmith */ 56677424Smsmith 56799679Siwasaki /*lint -fallthrough */ 56877424Smsmith 56977424Smsmith 570107325Siwasaki case ACPI_TYPE_LOCAL_REGION_FIELD: 57187031Smsmith /* 57287031Smsmith * For simple RegionFields, we just directly access the owning 57387031Smsmith * Operation Region. 57487031Smsmith */ 57587031Smsmith Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value, 576167802Sjkim ReadWrite); 57787031Smsmith break; 57887031Smsmith 57987031Smsmith 580107325Siwasaki case ACPI_TYPE_LOCAL_INDEX_FIELD: 58187031Smsmith 58287031Smsmith 583151937Sjkim /* 584151937Sjkim * Ensure that the IndexValue is not beyond the capacity of 585151937Sjkim * the register 586151937Sjkim */ 58787031Smsmith if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, 588202771Sjkim (UINT64) ObjDesc->IndexField.Value)) 58977424Smsmith { 59087031Smsmith return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 59177424Smsmith } 59287031Smsmith 59387031Smsmith /* Write the index value to the IndexRegister (itself a RegionField) */ 59487031Smsmith 595122944Snjl FieldDatumByteOffset += ObjDesc->IndexField.Value; 596122944Snjl 597122944Snjl ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 598167802Sjkim "Write to Index Register: Value %8.8X\n", 599167802Sjkim FieldDatumByteOffset)); 600122944Snjl 60187031Smsmith Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, 602167802Sjkim &FieldDatumByteOffset, 603167802Sjkim sizeof (FieldDatumByteOffset)); 60487031Smsmith if (ACPI_FAILURE (Status)) 60587031Smsmith { 60687031Smsmith return_ACPI_STATUS (Status); 60787031Smsmith } 60887031Smsmith 60987031Smsmith if (ReadWrite == ACPI_READ) 61087031Smsmith { 61187031Smsmith /* Read the datum from the DataRegister */ 61287031Smsmith 613193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 614193267Sjkim "Read from Data Register\n")); 615193267Sjkim 61687031Smsmith Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj, 617202771Sjkim Value, sizeof (UINT64)); 61887031Smsmith } 61987031Smsmith else 62087031Smsmith { 621122944Snjl /* Write the datum to the DataRegister */ 62287031Smsmith 623193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 624193267Sjkim "Write to Data Register: Value %8.8X%8.8X\n", 625193267Sjkim ACPI_FORMAT_UINT64 (*Value))); 626193267Sjkim 62787031Smsmith Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj, 628202771Sjkim Value, sizeof (UINT64)); 62987031Smsmith } 63077424Smsmith break; 63177424Smsmith 63277424Smsmith 63377424Smsmith default: 63477424Smsmith 635204773Sjkim ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u", 636193267Sjkim ObjDesc->Common.Type)); 63777424Smsmith Status = AE_AML_INTERNAL; 63877424Smsmith break; 63967754Smsmith } 64067754Smsmith 64187031Smsmith if (ACPI_SUCCESS (Status)) 64287031Smsmith { 64387031Smsmith if (ReadWrite == ACPI_READ) 64487031Smsmith { 645151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 646209746Sjkim "Value Read %8.8X%8.8X, Width %u\n", 647151937Sjkim ACPI_FORMAT_UINT64 (*Value), 648151937Sjkim ObjDesc->CommonField.AccessByteWidth)); 64987031Smsmith } 65087031Smsmith else 65187031Smsmith { 652151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 653209746Sjkim "Value Written %8.8X%8.8X, Width %u\n", 654151937Sjkim ACPI_FORMAT_UINT64 (*Value), 655151937Sjkim ObjDesc->CommonField.AccessByteWidth)); 65687031Smsmith } 65787031Smsmith } 65877424Smsmith 65987031Smsmith return_ACPI_STATUS (Status); 66087031Smsmith} 66177424Smsmith 66287031Smsmith 66387031Smsmith/******************************************************************************* 66487031Smsmith * 66587031Smsmith * FUNCTION: AcpiExWriteWithUpdateRule 66687031Smsmith * 667151937Sjkim * PARAMETERS: ObjDesc - Field to be written 668151937Sjkim * Mask - bitmask within field datum 669151937Sjkim * FieldValue - Value to write 670151937Sjkim * FieldDatumByteOffset - Offset of datum within field 67187031Smsmith * 67287031Smsmith * RETURN: Status 67387031Smsmith * 67487031Smsmith * DESCRIPTION: Apply the field update rule to a field write 67587031Smsmith * 67687031Smsmith ******************************************************************************/ 67787031Smsmith 67887031SmsmithACPI_STATUS 67987031SmsmithAcpiExWriteWithUpdateRule ( 68087031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 681202771Sjkim UINT64 Mask, 682202771Sjkim UINT64 FieldValue, 68387031Smsmith UINT32 FieldDatumByteOffset) 68487031Smsmith{ 68587031Smsmith ACPI_STATUS Status = AE_OK; 686202771Sjkim UINT64 MergedValue; 687202771Sjkim UINT64 CurrentValue; 68887031Smsmith 68987031Smsmith 690167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask); 69187031Smsmith 69287031Smsmith 69387031Smsmith /* Start with the new bits */ 69487031Smsmith 69587031Smsmith MergedValue = FieldValue; 69687031Smsmith 69787031Smsmith /* If the mask is all ones, we don't need to worry about the update rule */ 69887031Smsmith 699202771Sjkim if (Mask != ACPI_UINT64_MAX) 70087031Smsmith { 70187031Smsmith /* Decode the update rule */ 70287031Smsmith 70387031Smsmith switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) 70487031Smsmith { 70587031Smsmith case AML_FIELD_UPDATE_PRESERVE: 70687031Smsmith /* 70787031Smsmith * Check if update rule needs to be applied (not if mask is all 70887031Smsmith * ones) The left shift drops the bits we want to ignore. 70987031Smsmith */ 71091116Smsmith if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - 71191116Smsmith ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) 71287031Smsmith { 71387031Smsmith /* 71487031Smsmith * Read the current contents of the byte/word/dword containing 71587031Smsmith * the field, and merge with the new field value. 71687031Smsmith */ 71787031Smsmith Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 718167802Sjkim &CurrentValue, ACPI_READ); 719123315Snjl if (ACPI_FAILURE (Status)) 720123315Snjl { 721123315Snjl return_ACPI_STATUS (Status); 722123315Snjl } 723123315Snjl 72487031Smsmith MergedValue |= (CurrentValue & ~Mask); 72587031Smsmith } 72687031Smsmith break; 72787031Smsmith 72887031Smsmith case AML_FIELD_UPDATE_WRITE_AS_ONES: 72987031Smsmith 73087031Smsmith /* Set positions outside the field to all ones */ 73187031Smsmith 73287031Smsmith MergedValue |= ~Mask; 73387031Smsmith break; 73487031Smsmith 73587031Smsmith case AML_FIELD_UPDATE_WRITE_AS_ZEROS: 73687031Smsmith 73787031Smsmith /* Set positions outside the field to all zeros */ 73887031Smsmith 73987031Smsmith MergedValue &= Mask; 74087031Smsmith break; 74187031Smsmith 74287031Smsmith default: 743123315Snjl 744167802Sjkim ACPI_ERROR ((AE_INFO, 745204773Sjkim "Unknown UpdateRule value: 0x%X", 74687031Smsmith (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); 74787031Smsmith return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 74887031Smsmith } 74987031Smsmith } 75087031Smsmith 751123315Snjl ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 752123315Snjl "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", 753123315Snjl ACPI_FORMAT_UINT64 (Mask), 754123315Snjl FieldDatumByteOffset, 755123315Snjl ObjDesc->CommonField.AccessByteWidth, 756123315Snjl ACPI_FORMAT_UINT64 (FieldValue), 757123315Snjl ACPI_FORMAT_UINT64 (MergedValue))); 758123315Snjl 75987031Smsmith /* Write the merged value */ 76087031Smsmith 76187031Smsmith Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 762167802Sjkim &MergedValue, ACPI_WRITE); 76387031Smsmith 76477424Smsmith return_ACPI_STATUS (Status); 76577424Smsmith} 76677424Smsmith 76777424Smsmith 76877424Smsmith/******************************************************************************* 76977424Smsmith * 77077424Smsmith * FUNCTION: AcpiExExtractFromField 77167754Smsmith * 772131440Smarks * PARAMETERS: ObjDesc - Field to be read 773131440Smarks * Buffer - Where to store the field data 774131440Smarks * BufferLength - Length of Buffer 77567754Smsmith * 77667754Smsmith * RETURN: Status 77767754Smsmith * 778131440Smarks * DESCRIPTION: Retrieve the current value of the given field 77967754Smsmith * 78067754Smsmith ******************************************************************************/ 78167754Smsmith 78267754SmsmithACPI_STATUS 78377424SmsmithAcpiExExtractFromField ( 78467754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 78567754Smsmith void *Buffer, 78677424Smsmith UINT32 BufferLength) 78767754Smsmith{ 78867754Smsmith ACPI_STATUS Status; 789202771Sjkim UINT64 RawDatum; 790202771Sjkim UINT64 MergedDatum; 791151937Sjkim UINT32 FieldOffset = 0; 792151937Sjkim UINT32 BufferOffset = 0; 793151937Sjkim UINT32 BufferTailBits; 79477424Smsmith UINT32 DatumCount; 795151937Sjkim UINT32 FieldDatumCount; 796210976Sjkim UINT32 AccessBitWidth; 797123315Snjl UINT32 i; 79867754Smsmith 79967754Smsmith 800167802Sjkim ACPI_FUNCTION_TRACE (ExExtractFromField); 80167754Smsmith 80277424Smsmith 803151937Sjkim /* Validate target buffer and clear it */ 80477424Smsmith 805167802Sjkim if (BufferLength < 806210976Sjkim ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength)) 807151937Sjkim { 808167802Sjkim ACPI_ERROR ((AE_INFO, 809204773Sjkim "Field size %u (bits) is too large for buffer (%u)", 810151937Sjkim ObjDesc->CommonField.BitLength, BufferLength)); 811151937Sjkim 812151937Sjkim return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 813151937Sjkim } 814210976Sjkim 815151937Sjkim ACPI_MEMSET (Buffer, 0, BufferLength); 816210976Sjkim AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 817151937Sjkim 818210976Sjkim /* Handle the simple case here */ 819210976Sjkim 820210976Sjkim if ((ObjDesc->CommonField.StartFieldBitOffset == 0) && 821210976Sjkim (ObjDesc->CommonField.BitLength == AccessBitWidth)) 822210976Sjkim { 823210976Sjkim Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ); 824210976Sjkim return_ACPI_STATUS (Status); 825210976Sjkim } 826210976Sjkim 827210976Sjkim/* TBD: Move to common setup code */ 828210976Sjkim 829210976Sjkim /* Field algorithm is limited to sizeof(UINT64), truncate if needed */ 830210976Sjkim 831210976Sjkim if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 832210976Sjkim { 833210976Sjkim ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 834210976Sjkim AccessBitWidth = sizeof (UINT64) * 8; 835210976Sjkim } 836210976Sjkim 837151937Sjkim /* Compute the number of datums (access width data items) */ 838151937Sjkim 839151937Sjkim DatumCount = ACPI_ROUND_UP_TO ( 840210976Sjkim ObjDesc->CommonField.BitLength, AccessBitWidth); 841210976Sjkim 842151937Sjkim FieldDatumCount = ACPI_ROUND_UP_TO ( 843210976Sjkim ObjDesc->CommonField.BitLength + 844210976Sjkim ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); 845151937Sjkim 846151937Sjkim /* Priming read from the field */ 847151937Sjkim 848151937Sjkim Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); 849131440Smarks if (ACPI_FAILURE (Status)) 850123315Snjl { 851131440Smarks return_ACPI_STATUS (Status); 852123315Snjl } 853151937Sjkim MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 854123315Snjl 855151937Sjkim /* Read the rest of the field */ 85667754Smsmith 857151937Sjkim for (i = 1; i < FieldDatumCount; i++) 858151937Sjkim { 859151937Sjkim /* Get next input datum from the field */ 86067754Smsmith 861151937Sjkim FieldOffset += ObjDesc->CommonField.AccessByteWidth; 862151937Sjkim Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, 863167802Sjkim &RawDatum, ACPI_READ); 864123315Snjl if (ACPI_FAILURE (Status)) 865123315Snjl { 866123315Snjl return_ACPI_STATUS (Status); 867123315Snjl } 86867754Smsmith 869167802Sjkim /* 870167802Sjkim * Merge with previous datum if necessary. 871167802Sjkim * 872167802Sjkim * Note: Before the shift, check if the shift value will be larger than 873167802Sjkim * the integer size. If so, there is no need to perform the operation. 874167802Sjkim * This avoids the differences in behavior between different compilers 875167802Sjkim * concerning shift values larger than the target data width. 876167802Sjkim */ 877210976Sjkim if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset < 878210976Sjkim ACPI_INTEGER_BIT_SIZE) 879167802Sjkim { 880167802Sjkim MergedDatum |= RawDatum << 881210976Sjkim (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 882167802Sjkim } 88367754Smsmith 884151937Sjkim if (i == DatumCount) 88567754Smsmith { 886151937Sjkim break; 88777424Smsmith } 88867754Smsmith 889151937Sjkim /* Write merged datum to target buffer */ 89071867Smsmith 891151937Sjkim ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 892151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 893167802Sjkim BufferLength - BufferOffset)); 89467754Smsmith 895151937Sjkim BufferOffset += ObjDesc->CommonField.AccessByteWidth; 896151937Sjkim MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 897151937Sjkim } 898123315Snjl 899151937Sjkim /* Mask off any extra bits in the last datum */ 900123315Snjl 901210976Sjkim BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth; 902151937Sjkim if (BufferTailBits) 903151937Sjkim { 904151937Sjkim MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 905123315Snjl } 906123315Snjl 907151937Sjkim /* Write the last datum to the buffer */ 908123315Snjl 909151937Sjkim ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 910151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 911167802Sjkim BufferLength - BufferOffset)); 912123315Snjl 91377424Smsmith return_ACPI_STATUS (AE_OK); 91467754Smsmith} 91567754Smsmith 91667754Smsmith 91767754Smsmith/******************************************************************************* 91867754Smsmith * 91977424Smsmith * FUNCTION: AcpiExInsertIntoField 92067754Smsmith * 921131440Smarks * PARAMETERS: ObjDesc - Field to be written 922131440Smarks * Buffer - Data to be written 923131440Smarks * BufferLength - Length of Buffer 92467754Smsmith * 92567754Smsmith * RETURN: Status 92667754Smsmith * 927131440Smarks * DESCRIPTION: Store the Buffer contents into the given field 92867754Smsmith * 92977424Smsmith ******************************************************************************/ 93067754Smsmith 93167754SmsmithACPI_STATUS 93277424SmsmithAcpiExInsertIntoField ( 93367754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 93467754Smsmith void *Buffer, 93577424Smsmith UINT32 BufferLength) 93667754Smsmith{ 937210976Sjkim void *NewBuffer; 93867754Smsmith ACPI_STATUS Status; 939202771Sjkim UINT64 Mask; 940202771Sjkim UINT64 WidthMask; 941202771Sjkim UINT64 MergedDatum; 942202771Sjkim UINT64 RawDatum = 0; 943151937Sjkim UINT32 FieldOffset = 0; 944151937Sjkim UINT32 BufferOffset = 0; 945151937Sjkim UINT32 BufferTailBits; 94677424Smsmith UINT32 DatumCount; 947151937Sjkim UINT32 FieldDatumCount; 948210976Sjkim UINT32 AccessBitWidth; 949210976Sjkim UINT32 RequiredLength; 950151937Sjkim UINT32 i; 95167754Smsmith 95267754Smsmith 953167802Sjkim ACPI_FUNCTION_TRACE (ExInsertIntoField); 95467754Smsmith 95567754Smsmith 956151937Sjkim /* Validate input buffer */ 957131440Smarks 958193267Sjkim NewBuffer = NULL; 959193267Sjkim RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( 960193267Sjkim ObjDesc->CommonField.BitLength); 961193267Sjkim /* 962193267Sjkim * We must have a buffer that is at least as long as the field 963193267Sjkim * we are writing to. This is because individual fields are 964193267Sjkim * indivisible and partial writes are not supported -- as per 965193267Sjkim * the ACPI specification. 966193267Sjkim */ 967193267Sjkim if (BufferLength < RequiredLength) 96877424Smsmith { 969193267Sjkim /* We need to create a new buffer */ 970151937Sjkim 971193267Sjkim NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); 972193267Sjkim if (!NewBuffer) 973193267Sjkim { 974193267Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 975193267Sjkim } 976193267Sjkim 977193267Sjkim /* 978193267Sjkim * Copy the original data to the new buffer, starting 979193267Sjkim * at Byte zero. All unused (upper) bytes of the 980193267Sjkim * buffer will be 0. 981193267Sjkim */ 982193267Sjkim ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength); 983193267Sjkim Buffer = NewBuffer; 984193267Sjkim BufferLength = RequiredLength; 98577424Smsmith } 98667754Smsmith 987210976Sjkim/* TBD: Move to common setup code */ 988210976Sjkim 989210976Sjkim /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */ 990210976Sjkim if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 991210976Sjkim { 992210976Sjkim ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 993210976Sjkim } 994210976Sjkim 995210976Sjkim AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 996210976Sjkim 997167802Sjkim /* 998167802Sjkim * Create the bitmasks used for bit insertion. 999167802Sjkim * Note: This if/else is used to bypass compiler differences with the 1000167802Sjkim * shift operator 1001167802Sjkim */ 1002210976Sjkim if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE) 1003167802Sjkim { 1004202771Sjkim WidthMask = ACPI_UINT64_MAX; 1005167802Sjkim } 1006167802Sjkim else 1007167802Sjkim { 1008210976Sjkim WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth); 1009167802Sjkim } 1010167802Sjkim 1011167802Sjkim Mask = WidthMask & 1012210976Sjkim ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); 1013167802Sjkim 1014151937Sjkim /* Compute the number of datums (access width data items) */ 101567754Smsmith 1016151937Sjkim DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, 1017210976Sjkim AccessBitWidth); 1018167802Sjkim 1019151937Sjkim FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + 1020210976Sjkim ObjDesc->CommonField.StartFieldBitOffset, 1021210976Sjkim AccessBitWidth); 102267754Smsmith 1023151937Sjkim /* Get initial Datum from the input buffer */ 102467754Smsmith 1025151937Sjkim ACPI_MEMCPY (&RawDatum, Buffer, 1026151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 1027167802Sjkim BufferLength - BufferOffset)); 102867754Smsmith 1029151937Sjkim MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 103067754Smsmith 1031151937Sjkim /* Write the entire field */ 103267754Smsmith 1033151937Sjkim for (i = 1; i < FieldDatumCount; i++) 103467754Smsmith { 1035151937Sjkim /* Write merged datum to the target field */ 103667754Smsmith 1037151937Sjkim MergedDatum &= Mask; 1038151937Sjkim Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, 1039151937Sjkim MergedDatum, FieldOffset); 1040151937Sjkim if (ACPI_FAILURE (Status)) 1041151937Sjkim { 1042193267Sjkim goto Exit; 1043151937Sjkim } 1044123315Snjl 1045151937Sjkim FieldOffset += ObjDesc->CommonField.AccessByteWidth; 104667754Smsmith 1047167802Sjkim /* 1048167802Sjkim * Start new output datum by merging with previous input datum 1049167802Sjkim * if necessary. 1050167802Sjkim * 1051167802Sjkim * Note: Before the shift, check if the shift value will be larger than 1052167802Sjkim * the integer size. If so, there is no need to perform the operation. 1053167802Sjkim * This avoids the differences in behavior between different compilers 1054167802Sjkim * concerning shift values larger than the target data width. 1055167802Sjkim */ 1056210976Sjkim if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) < 1057210976Sjkim ACPI_INTEGER_BIT_SIZE) 1058167802Sjkim { 1059167802Sjkim MergedDatum = RawDatum >> 1060210976Sjkim (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 1061167802Sjkim } 1062167802Sjkim else 1063167802Sjkim { 1064167802Sjkim MergedDatum = 0; 1065167802Sjkim } 1066167802Sjkim 1067167802Sjkim Mask = WidthMask; 1068167802Sjkim 1069151937Sjkim if (i == DatumCount) 107067754Smsmith { 1071151937Sjkim break; 107267754Smsmith } 107377424Smsmith 1074151937Sjkim /* Get the next input datum from the buffer */ 107567754Smsmith 1076151937Sjkim BufferOffset += ObjDesc->CommonField.AccessByteWidth; 1077151937Sjkim ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset, 1078151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 1079210976Sjkim BufferLength - BufferOffset)); 1080210976Sjkim 1081151937Sjkim MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 1082151937Sjkim } 108367754Smsmith 1084151937Sjkim /* Mask off any extra bits in the last datum */ 108567754Smsmith 1086151937Sjkim BufferTailBits = (ObjDesc->CommonField.BitLength + 1087210976Sjkim ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth; 1088151937Sjkim if (BufferTailBits) 1089151937Sjkim { 1090151937Sjkim Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 1091151937Sjkim } 1092123315Snjl 1093151937Sjkim /* Write the last datum to the field */ 109467754Smsmith 1095151937Sjkim MergedDatum &= Mask; 1096151937Sjkim Status = AcpiExWriteWithUpdateRule (ObjDesc, 1097151937Sjkim Mask, MergedDatum, FieldOffset); 109867754Smsmith 1099193267SjkimExit: 1100193267Sjkim /* Free temporary buffer if we used one */ 1101193267Sjkim 1102193267Sjkim if (NewBuffer) 1103193267Sjkim { 1104193267Sjkim ACPI_FREE (NewBuffer); 1105193267Sjkim } 110667754Smsmith return_ACPI_STATUS (Status); 110767754Smsmith} 110867754Smsmith 110967754Smsmith 1110