exfldio.c revision 228110
1289848Sjkim/****************************************************************************** 2289848Sjkim * 3289848Sjkim * Module Name: exfldio - Aml Field I/O 4289848Sjkim * 5289848Sjkim *****************************************************************************/ 6289848Sjkim 7289848Sjkim/* 8289848Sjkim * Copyright (C) 2000 - 2011, Intel Corp. 9289848Sjkim * All rights reserved. 10289848Sjkim * 11289848Sjkim * Redistribution and use in source and binary forms, with or without 12289848Sjkim * modification, are permitted provided that the following conditions 13289848Sjkim * are met: 14289848Sjkim * 1. Redistributions of source code must retain the above copyright 15289848Sjkim * notice, this list of conditions, and the following disclaimer, 16289848Sjkim * without modification. 17289848Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18289848Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19289848Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20289848Sjkim * including a substantially similar Disclaimer requirement for further 21289848Sjkim * binary redistribution. 22289848Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23289848Sjkim * of any contributors may be used to endorse or promote products derived 24289848Sjkim * from this software without specific prior written permission. 25289848Sjkim * 26289848Sjkim * Alternatively, this software may be distributed under the terms of the 27289848Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28289848Sjkim * Software Foundation. 29289848Sjkim * 30289848Sjkim * NO WARRANTY 31289848Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32289848Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33289848Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34289848Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35289848Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36289848Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37289848Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38289848Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39289848Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40289848Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41289848Sjkim * POSSIBILITY OF SUCH DAMAGES. 42289848Sjkim */ 43289848Sjkim 44289848Sjkim 45289848Sjkim#define __EXFLDIO_C__ 46289848Sjkim 47289848Sjkim#include <contrib/dev/acpica/include/acpi.h> 48289848Sjkim#include <contrib/dev/acpica/include/accommon.h> 49289848Sjkim#include <contrib/dev/acpica/include/acinterp.h> 50289848Sjkim#include <contrib/dev/acpica/include/amlcode.h> 51289848Sjkim#include <contrib/dev/acpica/include/acevents.h> 52289848Sjkim#include <contrib/dev/acpica/include/acdispat.h> 53289848Sjkim 54289848Sjkim 55289848Sjkim#define _COMPONENT ACPI_EXECUTER 56289848Sjkim ACPI_MODULE_NAME ("exfldio") 57289848Sjkim 58289848Sjkim/* Local prototypes */ 59289848Sjkim 60289848Sjkimstatic ACPI_STATUS 61289848SjkimAcpiExFieldDatumIo ( 62289848Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 63289848Sjkim UINT32 FieldDatumByteOffset, 64289848Sjkim UINT64 *Value, 65289848Sjkim UINT32 ReadWrite); 66289848Sjkim 67289848Sjkimstatic BOOLEAN 68289848SjkimAcpiExRegisterOverflow ( 69289848Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 70289848Sjkim UINT64 Value); 71289848Sjkim 72289848Sjkimstatic ACPI_STATUS 73289848SjkimAcpiExSetupRegion ( 74289848Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 75289848Sjkim UINT32 FieldDatumByteOffset); 76289848Sjkim 77289848Sjkim 78289848Sjkim/******************************************************************************* 79289848Sjkim * 80289848Sjkim * FUNCTION: AcpiExSetupRegion 81289848Sjkim * 82289848Sjkim * PARAMETERS: ObjDesc - Field to be read or written 83289848Sjkim * FieldDatumByteOffset - Byte offset of this datum within the 84289848Sjkim * parent field 85289848Sjkim * 86289848Sjkim * RETURN: Status 87289848Sjkim * 88289848Sjkim * DESCRIPTION: Common processing for AcpiExExtractFromField and 89289848Sjkim * AcpiExInsertIntoField. Initialize the Region if necessary and 90289848Sjkim * validate the request. 91289848Sjkim * 92289848Sjkim ******************************************************************************/ 93289848Sjkim 94289848Sjkimstatic ACPI_STATUS 95289848SjkimAcpiExSetupRegion ( 96289848Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 97289848Sjkim UINT32 FieldDatumByteOffset) 98289848Sjkim{ 99306198Sjkim ACPI_STATUS Status = AE_OK; 100289848Sjkim ACPI_OPERAND_OBJECT *RgnDesc; 101289848Sjkim UINT8 SpaceId; 102289848Sjkim 103289848Sjkim 104289848Sjkim ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset); 105289848Sjkim 106289848Sjkim 107289848Sjkim RgnDesc = ObjDesc->CommonField.RegionObj; 108289848Sjkim 109289848Sjkim /* We must have a valid region */ 110289848Sjkim 111289848Sjkim if (RgnDesc->Common.Type != ACPI_TYPE_REGION) 112289848Sjkim { 113289848Sjkim ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)", 114289848Sjkim RgnDesc->Common.Type, 115289848Sjkim AcpiUtGetObjectTypeName (RgnDesc))); 116289848Sjkim 117289848Sjkim return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 118289848Sjkim } 119289848Sjkim 120289848Sjkim SpaceId = RgnDesc->Region.SpaceId; 121289848Sjkim 122289848Sjkim /* Validate the Space ID */ 123289848Sjkim 124289848Sjkim if (!AcpiIsValidSpaceId (SpaceId)) 125289848Sjkim { 126289848Sjkim ACPI_ERROR ((AE_INFO, "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId)); 127289848Sjkim return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID); 128289848Sjkim } 129289848Sjkim 130289848Sjkim /* 131289848Sjkim * If the Region Address and Length have not been previously evaluated, 132289848Sjkim * evaluate them now and save the results. 133289848Sjkim */ 134289848Sjkim if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) 135289848Sjkim { 136289848Sjkim Status = AcpiDsGetRegionArguments (RgnDesc); 137289848Sjkim if (ACPI_FAILURE (Status)) 138289848Sjkim { 139289848Sjkim return_ACPI_STATUS (Status); 140289848Sjkim } 141289848Sjkim } 142289848Sjkim 143289848Sjkim /* 144289848Sjkim * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear 145289848Sjkim * address space and the request cannot be directly validated 146289848Sjkim */ 147289848Sjkim if (SpaceId == ACPI_ADR_SPACE_SMBUS || 148289848Sjkim SpaceId == ACPI_ADR_SPACE_GSBUS || 149289848Sjkim SpaceId == ACPI_ADR_SPACE_IPMI) 150289848Sjkim { 151289848Sjkim /* SMBus or IPMI has a non-linear address space */ 152289848Sjkim 153289848Sjkim return_ACPI_STATUS (AE_OK); 154289848Sjkim } 155289848Sjkim 156289848Sjkim#ifdef ACPI_UNDER_DEVELOPMENT 157289848Sjkim /* 158289848Sjkim * If the Field access is AnyAcc, we can now compute the optimal 159289848Sjkim * access (because we know know the length of the parent region) 160289848Sjkim */ 161289848Sjkim if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 162289848Sjkim { 163289848Sjkim if (ACPI_FAILURE (Status)) 164289848Sjkim { 165289848Sjkim return_ACPI_STATUS (Status); 166289848Sjkim } 167289848Sjkim } 168289848Sjkim#endif 169289848Sjkim 170289848Sjkim /* 171289848Sjkim * Validate the request. The entire request from the byte offset for a 172289848Sjkim * length of one field datum (access width) must fit within the region. 173289848Sjkim * (Region length is specified in bytes) 174289848Sjkim */ 175289848Sjkim if (RgnDesc->Region.Length < 176289848Sjkim (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset + 177289848Sjkim ObjDesc->CommonField.AccessByteWidth)) 178289848Sjkim { 179289848Sjkim if (AcpiGbl_EnableInterpreterSlack) 180289848Sjkim { 181289848Sjkim /* 182289848Sjkim * Slack mode only: We will go ahead and allow access to this 183289848Sjkim * field if it is within the region length rounded up to the next 184289848Sjkim * access width boundary. ACPI_SIZE cast for 64-bit compile. 185289848Sjkim */ 186289848Sjkim if (ACPI_ROUND_UP (RgnDesc->Region.Length, 187289848Sjkim ObjDesc->CommonField.AccessByteWidth) >= 188289848Sjkim ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset + 189289848Sjkim ObjDesc->CommonField.AccessByteWidth + 190289848Sjkim FieldDatumByteOffset)) 191289848Sjkim { 192289848Sjkim return_ACPI_STATUS (AE_OK); 193289848Sjkim } 194289848Sjkim } 195289848Sjkim 196289848Sjkim if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth) 197289848Sjkim { 198289848Sjkim /* 199289848Sjkim * This is the case where the AccessType (AccWord, etc.) is wider 200306198Sjkim * than the region itself. For example, a region of length one 201289848Sjkim * byte, and a field with Dword access specified. 202289848Sjkim */ 203289848Sjkim ACPI_ERROR ((AE_INFO, 204289848Sjkim "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)", 205289848Sjkim AcpiUtGetNodeName (ObjDesc->CommonField.Node), 206289848Sjkim ObjDesc->CommonField.AccessByteWidth, 207289848Sjkim AcpiUtGetNodeName (RgnDesc->Region.Node), 208289848Sjkim RgnDesc->Region.Length)); 209289848Sjkim } 210289848Sjkim 211289848Sjkim /* 212289848Sjkim * Offset rounded up to next multiple of field width 213289848Sjkim * exceeds region length, indicate an error 214289848Sjkim */ 215289848Sjkim ACPI_ERROR ((AE_INFO, 216289848Sjkim "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)", 217289848Sjkim AcpiUtGetNodeName (ObjDesc->CommonField.Node), 218289848Sjkim ObjDesc->CommonField.BaseByteOffset, 219289848Sjkim FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, 220289848Sjkim AcpiUtGetNodeName (RgnDesc->Region.Node), 221289848Sjkim RgnDesc->Region.Length)); 222289848Sjkim 223289848Sjkim return_ACPI_STATUS (AE_AML_REGION_LIMIT); 224289848Sjkim } 225289848Sjkim 226289848Sjkim return_ACPI_STATUS (AE_OK); 227289848Sjkim} 228289848Sjkim 229289848Sjkim 230289848Sjkim/******************************************************************************* 231289848Sjkim * 232289848Sjkim * FUNCTION: AcpiExAccessRegion 233289848Sjkim * 234289848Sjkim * PARAMETERS: ObjDesc - Field to be read 235289848Sjkim * FieldDatumByteOffset - Byte offset of this datum within the 236289848Sjkim * parent field 237289848Sjkim * Value - Where to store value (must at least 238289848Sjkim * 64 bits) 239289848Sjkim * Function - Read or Write flag plus other region- 240289848Sjkim * dependent flags 241289848Sjkim * 242289848Sjkim * RETURN: Status 243289848Sjkim * 244289848Sjkim * DESCRIPTION: Read or Write a single field datum to an Operation Region. 245289848Sjkim * 246289848Sjkim ******************************************************************************/ 247289848Sjkim 248289848SjkimACPI_STATUS 249289848SjkimAcpiExAccessRegion ( 250289848Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 251289848Sjkim UINT32 FieldDatumByteOffset, 252289848Sjkim UINT64 *Value, 253289848Sjkim UINT32 Function) 254289848Sjkim{ 255289848Sjkim ACPI_STATUS Status; 256289848Sjkim ACPI_OPERAND_OBJECT *RgnDesc; 257289848Sjkim UINT32 RegionOffset; 258289848Sjkim 259289848Sjkim 260289848Sjkim ACPI_FUNCTION_TRACE (ExAccessRegion); 261289848Sjkim 262289848Sjkim 263289848Sjkim /* 264289848Sjkim * Ensure that the region operands are fully evaluated and verify 265289848Sjkim * the validity of the request 266289848Sjkim */ 267289848Sjkim Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset); 268289848Sjkim if (ACPI_FAILURE (Status)) 269289848Sjkim { 270289848Sjkim return_ACPI_STATUS (Status); 271289848Sjkim } 272289848Sjkim 273289848Sjkim /* 274289848Sjkim * The physical address of this field datum is: 275289848Sjkim * 276289848Sjkim * 1) The base of the region, plus 277289848Sjkim * 2) The base offset of the field, plus 278289848Sjkim * 3) The current offset into the field 279289848Sjkim */ 280289848Sjkim RgnDesc = ObjDesc->CommonField.RegionObj; 281289848Sjkim RegionOffset = 282289848Sjkim ObjDesc->CommonField.BaseByteOffset + 283289848Sjkim FieldDatumByteOffset; 284289848Sjkim 285289848Sjkim if ((Function & ACPI_IO_MASK) == ACPI_READ) 286289848Sjkim { 287289848Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); 288289848Sjkim } 289289848Sjkim else 290289848Sjkim { 291289848Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); 292289848Sjkim } 293289848Sjkim 294289848Sjkim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, 295289848Sjkim " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", 296289848Sjkim AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 297289848Sjkim RgnDesc->Region.SpaceId, 298289848Sjkim ObjDesc->CommonField.AccessByteWidth, 299289848Sjkim ObjDesc->CommonField.BaseByteOffset, 300289848Sjkim FieldDatumByteOffset, 301289848Sjkim ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset)))); 302289848Sjkim 303289848Sjkim /* Invoke the appropriate AddressSpace/OpRegion handler */ 304289848Sjkim 305289848Sjkim Status = AcpiEvAddressSpaceDispatch (RgnDesc, ObjDesc, 306289848Sjkim Function, RegionOffset, 307289848Sjkim ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); 308306198Sjkim 309289848Sjkim if (ACPI_FAILURE (Status)) 310289848Sjkim { 311289848Sjkim if (Status == AE_NOT_IMPLEMENTED) 312289848Sjkim { 313289848Sjkim ACPI_ERROR ((AE_INFO, 314289848Sjkim "Region %s (ID=%u) not implemented", 315289848Sjkim AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 316289848Sjkim RgnDesc->Region.SpaceId)); 317289848Sjkim } 318289848Sjkim else if (Status == AE_NOT_EXIST) 319289848Sjkim { 320289848Sjkim ACPI_ERROR ((AE_INFO, 321289848Sjkim "Region %s (ID=%u) has no handler", 322289848Sjkim AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 323289848Sjkim RgnDesc->Region.SpaceId)); 324289848Sjkim } 325289848Sjkim } 326289848Sjkim 327289848Sjkim return_ACPI_STATUS (Status); 328289848Sjkim} 329289848Sjkim 330289848Sjkim 331289848Sjkim/******************************************************************************* 332289848Sjkim * 333289848Sjkim * FUNCTION: AcpiExRegisterOverflow 334289848Sjkim * 335289848Sjkim * PARAMETERS: ObjDesc - Register(Field) to be written 336289848Sjkim * Value - Value to be stored 337289848Sjkim * 338289848Sjkim * RETURN: TRUE if value overflows the field, FALSE otherwise 339289848Sjkim * 340289848Sjkim * DESCRIPTION: Check if a value is out of range of the field being written. 341289848Sjkim * Used to check if the values written to Index and Bank registers 342289848Sjkim * are out of range. Normally, the value is simply truncated 343289848Sjkim * to fit the field, but this case is most likely a serious 344289848Sjkim * coding error in the ASL. 345289848Sjkim * 346289848Sjkim ******************************************************************************/ 347289848Sjkim 348289848Sjkimstatic BOOLEAN 349289848SjkimAcpiExRegisterOverflow ( 350289848Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 351289848Sjkim UINT64 Value) 352289848Sjkim{ 353289848Sjkim ACPI_FUNCTION_NAME (ExRegisterOverflow); 354289848Sjkim 355289848Sjkim 356289848Sjkim if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE) 357289848Sjkim { 358289848Sjkim /* 359289848Sjkim * The field is large enough to hold the maximum integer, so we can 360289848Sjkim * never overflow it. 361289848Sjkim */ 362289848Sjkim return (FALSE); 363289848Sjkim } 364289848Sjkim 365289848Sjkim if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength)) 366289848Sjkim { 367289848Sjkim /* 368289848Sjkim * The Value is larger than the maximum value that can fit into 369289848Sjkim * the register. 370289848Sjkim */ 371289848Sjkim ACPI_ERROR ((AE_INFO, 372289848Sjkim "Index value 0x%8.8X%8.8X overflows field width 0x%X", 373289848Sjkim ACPI_FORMAT_UINT64 (Value), 374289848Sjkim ObjDesc->CommonField.BitLength)); 375289848Sjkim 376289848Sjkim return (TRUE); 377289848Sjkim } 378289848Sjkim 379289848Sjkim /* The Value will fit into the field with no truncation */ 380289848Sjkim 381289848Sjkim return (FALSE); 382289848Sjkim} 383289848Sjkim 384289848Sjkim 385289848Sjkim/******************************************************************************* 386289848Sjkim * 387289848Sjkim * FUNCTION: AcpiExFieldDatumIo 388289848Sjkim * 389289848Sjkim * PARAMETERS: ObjDesc - Field to be read 390289848Sjkim * FieldDatumByteOffset - Byte offset of this datum within the 391289848Sjkim * parent field 392289848Sjkim * Value - Where to store value (must be 64 bits) 393289848Sjkim * ReadWrite - Read or Write flag 394289848Sjkim * 395289848Sjkim * RETURN: Status 396289848Sjkim * 397289848Sjkim * DESCRIPTION: Read or Write a single datum of a field. The FieldType is 398289848Sjkim * demultiplexed here to handle the different types of fields 399289848Sjkim * (BufferField, RegionField, IndexField, BankField) 400289848Sjkim * 401289848Sjkim ******************************************************************************/ 402289848Sjkim 403289848Sjkimstatic ACPI_STATUS 404289848SjkimAcpiExFieldDatumIo ( 405289848Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 406289848Sjkim UINT32 FieldDatumByteOffset, 407289848Sjkim UINT64 *Value, 408289848Sjkim UINT32 ReadWrite) 409289848Sjkim{ 410289848Sjkim ACPI_STATUS Status; 411289848Sjkim UINT64 LocalValue; 412289848Sjkim 413289848Sjkim 414289848Sjkim ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset); 415289848Sjkim 416289848Sjkim 417289848Sjkim if (ReadWrite == ACPI_READ) 418289848Sjkim { 419289848Sjkim if (!Value) 420289848Sjkim { 421289848Sjkim LocalValue = 0; 422289848Sjkim 423289848Sjkim /* To support reads without saving return value */ 424289848Sjkim Value = &LocalValue; 425289848Sjkim } 426289848Sjkim 427289848Sjkim /* Clear the entire return buffer first, [Very Important!] */ 428289848Sjkim 429289848Sjkim *Value = 0; 430289848Sjkim } 431289848Sjkim 432289848Sjkim /* 433289848Sjkim * The four types of fields are: 434289848Sjkim * 435289848Sjkim * BufferField - Read/write from/to a Buffer 436289848Sjkim * RegionField - Read/write from/to a Operation Region. 437289848Sjkim * BankField - Write to a Bank Register, then read/write from/to an 438289848Sjkim * OperationRegion 439289848Sjkim * IndexField - Write to an Index Register, then read/write from/to a 440289848Sjkim * Data Register 441289848Sjkim */ 442289848Sjkim switch (ObjDesc->Common.Type) 443289848Sjkim { 444289848Sjkim case ACPI_TYPE_BUFFER_FIELD: 445289848Sjkim /* 446289848Sjkim * If the BufferField arguments have not been previously evaluated, 447289848Sjkim * evaluate them now and save the results. 448289848Sjkim */ 449289848Sjkim if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 450289848Sjkim { 451289848Sjkim Status = AcpiDsGetBufferFieldArguments (ObjDesc); 452289848Sjkim if (ACPI_FAILURE (Status)) 453289848Sjkim { 454289848Sjkim return_ACPI_STATUS (Status); 455289848Sjkim } 456289848Sjkim } 457289848Sjkim 458289848Sjkim if (ReadWrite == ACPI_READ) 459289848Sjkim { 460306198Sjkim /* 461289848Sjkim * Copy the data from the source buffer. 462289848Sjkim * Length is the field width in bytes. 463289848Sjkim */ 464289848Sjkim ACPI_MEMCPY (Value, 465289848Sjkim (ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 466289848Sjkim ObjDesc->BufferField.BaseByteOffset + 467289848Sjkim FieldDatumByteOffset, 468289848Sjkim ObjDesc->CommonField.AccessByteWidth); 469289848Sjkim } 470289848Sjkim else 471289848Sjkim { 472289848Sjkim /* 473289848Sjkim * Copy the data to the target buffer. 474289848Sjkim * Length is the field width in bytes. 475289848Sjkim */ 476289848Sjkim ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 477289848Sjkim ObjDesc->BufferField.BaseByteOffset + 478289848Sjkim FieldDatumByteOffset, 479289848Sjkim Value, ObjDesc->CommonField.AccessByteWidth); 480289848Sjkim } 481289848Sjkim 482289848Sjkim Status = AE_OK; 483289848Sjkim break; 484289848Sjkim 485289848Sjkim 486289848Sjkim case ACPI_TYPE_LOCAL_BANK_FIELD: 487289848Sjkim 488289848Sjkim /* 489289848Sjkim * Ensure that the BankValue is not beyond the capacity of 490289848Sjkim * the register 491289848Sjkim */ 492289848Sjkim if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, 493289848Sjkim (UINT64) ObjDesc->BankField.Value)) 494289848Sjkim { 495289848Sjkim return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 496289848Sjkim } 497289848Sjkim 498289848Sjkim /* 499289848Sjkim * For BankFields, we must write the BankValue to the BankRegister 500289848Sjkim * (itself a RegionField) before we can access the data. 501289848Sjkim */ 502289848Sjkim Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, 503289848Sjkim &ObjDesc->BankField.Value, 504289848Sjkim sizeof (ObjDesc->BankField.Value)); 505289848Sjkim if (ACPI_FAILURE (Status)) 506289848Sjkim { 507289848Sjkim return_ACPI_STATUS (Status); 508289848Sjkim } 509289848Sjkim 510289848Sjkim /* 511289848Sjkim * Now that the Bank has been selected, fall through to the 512289848Sjkim * RegionField case and write the datum to the Operation Region 513289848Sjkim */ 514289848Sjkim 515289848Sjkim /*lint -fallthrough */ 516289848Sjkim 517289848Sjkim 518289848Sjkim case ACPI_TYPE_LOCAL_REGION_FIELD: 519289848Sjkim /* 520289848Sjkim * For simple RegionFields, we just directly access the owning 521289848Sjkim * Operation Region. 522289848Sjkim */ 523289848Sjkim Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value, 524289848Sjkim ReadWrite); 525289848Sjkim break; 526289848Sjkim 527289848Sjkim 528289848Sjkim case ACPI_TYPE_LOCAL_INDEX_FIELD: 529289848Sjkim 530289848Sjkim 531289848Sjkim /* 532289848Sjkim * Ensure that the IndexValue is not beyond the capacity of 533289848Sjkim * the register 534289848Sjkim */ 535289848Sjkim if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, 536289848Sjkim (UINT64) ObjDesc->IndexField.Value)) 537289848Sjkim { 538289848Sjkim return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 539289848Sjkim } 540289848Sjkim 541289848Sjkim /* Write the index value to the IndexRegister (itself a RegionField) */ 542289848Sjkim 543289848Sjkim FieldDatumByteOffset += ObjDesc->IndexField.Value; 544289848Sjkim 545289848Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 546289848Sjkim "Write to Index Register: Value %8.8X\n", 547289848Sjkim FieldDatumByteOffset)); 548289848Sjkim 549289848Sjkim Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, 550289848Sjkim &FieldDatumByteOffset, 551289848Sjkim sizeof (FieldDatumByteOffset)); 552289848Sjkim if (ACPI_FAILURE (Status)) 553289848Sjkim { 554289848Sjkim return_ACPI_STATUS (Status); 555289848Sjkim } 556289848Sjkim 557289848Sjkim if (ReadWrite == ACPI_READ) 558289848Sjkim { 559289848Sjkim /* Read the datum from the DataRegister */ 560289848Sjkim 561289848Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 562289848Sjkim "Read from Data Register\n")); 563289848Sjkim 564289848Sjkim Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj, 565289848Sjkim Value, sizeof (UINT64)); 566289848Sjkim } 567289848Sjkim else 568289848Sjkim { 569289848Sjkim /* Write the datum to the DataRegister */ 570289848Sjkim 571289848Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 572289848Sjkim "Write to Data Register: Value %8.8X%8.8X\n", 573289848Sjkim ACPI_FORMAT_UINT64 (*Value))); 574289848Sjkim 575289848Sjkim Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj, 576289848Sjkim Value, sizeof (UINT64)); 577289848Sjkim } 578289848Sjkim break; 579289848Sjkim 580289848Sjkim 581289848Sjkim default: 582289848Sjkim 583289848Sjkim ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u", 584289848Sjkim ObjDesc->Common.Type)); 585289848Sjkim Status = AE_AML_INTERNAL; 586289848Sjkim break; 587289848Sjkim } 588289848Sjkim 589289848Sjkim if (ACPI_SUCCESS (Status)) 590289848Sjkim { 591289848Sjkim if (ReadWrite == ACPI_READ) 592289848Sjkim { 593289848Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 594289848Sjkim "Value Read %8.8X%8.8X, Width %u\n", 595289848Sjkim ACPI_FORMAT_UINT64 (*Value), 596289848Sjkim ObjDesc->CommonField.AccessByteWidth)); 597289848Sjkim } 598289848Sjkim else 599289848Sjkim { 600289848Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 601289848Sjkim "Value Written %8.8X%8.8X, Width %u\n", 602289848Sjkim ACPI_FORMAT_UINT64 (*Value), 603289848Sjkim ObjDesc->CommonField.AccessByteWidth)); 604289848Sjkim } 605289848Sjkim } 606289848Sjkim 607289848Sjkim return_ACPI_STATUS (Status); 608289848Sjkim} 609289848Sjkim 610289848Sjkim 611289848Sjkim/******************************************************************************* 612289848Sjkim * 613289848Sjkim * FUNCTION: AcpiExWriteWithUpdateRule 614289848Sjkim * 615289848Sjkim * PARAMETERS: ObjDesc - Field to be written 616289848Sjkim * Mask - bitmask within field datum 617289848Sjkim * FieldValue - Value to write 618 * FieldDatumByteOffset - Offset of datum within field 619 * 620 * RETURN: Status 621 * 622 * DESCRIPTION: Apply the field update rule to a field write 623 * 624 ******************************************************************************/ 625 626ACPI_STATUS 627AcpiExWriteWithUpdateRule ( 628 ACPI_OPERAND_OBJECT *ObjDesc, 629 UINT64 Mask, 630 UINT64 FieldValue, 631 UINT32 FieldDatumByteOffset) 632{ 633 ACPI_STATUS Status = AE_OK; 634 UINT64 MergedValue; 635 UINT64 CurrentValue; 636 637 638 ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask); 639 640 641 /* Start with the new bits */ 642 643 MergedValue = FieldValue; 644 645 /* If the mask is all ones, we don't need to worry about the update rule */ 646 647 if (Mask != ACPI_UINT64_MAX) 648 { 649 /* Decode the update rule */ 650 651 switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) 652 { 653 case AML_FIELD_UPDATE_PRESERVE: 654 /* 655 * Check if update rule needs to be applied (not if mask is all 656 * ones) The left shift drops the bits we want to ignore. 657 */ 658 if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - 659 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) 660 { 661 /* 662 * Read the current contents of the byte/word/dword containing 663 * the field, and merge with the new field value. 664 */ 665 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 666 &CurrentValue, ACPI_READ); 667 if (ACPI_FAILURE (Status)) 668 { 669 return_ACPI_STATUS (Status); 670 } 671 672 MergedValue |= (CurrentValue & ~Mask); 673 } 674 break; 675 676 case AML_FIELD_UPDATE_WRITE_AS_ONES: 677 678 /* Set positions outside the field to all ones */ 679 680 MergedValue |= ~Mask; 681 break; 682 683 case AML_FIELD_UPDATE_WRITE_AS_ZEROS: 684 685 /* Set positions outside the field to all zeros */ 686 687 MergedValue &= Mask; 688 break; 689 690 default: 691 692 ACPI_ERROR ((AE_INFO, 693 "Unknown UpdateRule value: 0x%X", 694 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); 695 return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 696 } 697 } 698 699 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 700 "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", 701 ACPI_FORMAT_UINT64 (Mask), 702 FieldDatumByteOffset, 703 ObjDesc->CommonField.AccessByteWidth, 704 ACPI_FORMAT_UINT64 (FieldValue), 705 ACPI_FORMAT_UINT64 (MergedValue))); 706 707 /* Write the merged value */ 708 709 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 710 &MergedValue, ACPI_WRITE); 711 712 return_ACPI_STATUS (Status); 713} 714 715 716/******************************************************************************* 717 * 718 * FUNCTION: AcpiExExtractFromField 719 * 720 * PARAMETERS: ObjDesc - Field to be read 721 * Buffer - Where to store the field data 722 * BufferLength - Length of Buffer 723 * 724 * RETURN: Status 725 * 726 * DESCRIPTION: Retrieve the current value of the given field 727 * 728 ******************************************************************************/ 729 730ACPI_STATUS 731AcpiExExtractFromField ( 732 ACPI_OPERAND_OBJECT *ObjDesc, 733 void *Buffer, 734 UINT32 BufferLength) 735{ 736 ACPI_STATUS Status; 737 UINT64 RawDatum; 738 UINT64 MergedDatum; 739 UINT32 FieldOffset = 0; 740 UINT32 BufferOffset = 0; 741 UINT32 BufferTailBits; 742 UINT32 DatumCount; 743 UINT32 FieldDatumCount; 744 UINT32 AccessBitWidth; 745 UINT32 i; 746 747 748 ACPI_FUNCTION_TRACE (ExExtractFromField); 749 750 751 /* Validate target buffer and clear it */ 752 753 if (BufferLength < 754 ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength)) 755 { 756 ACPI_ERROR ((AE_INFO, 757 "Field size %u (bits) is too large for buffer (%u)", 758 ObjDesc->CommonField.BitLength, BufferLength)); 759 760 return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 761 } 762 763 ACPI_MEMSET (Buffer, 0, BufferLength); 764 AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 765 766 /* Handle the simple case here */ 767 768 if ((ObjDesc->CommonField.StartFieldBitOffset == 0) && 769 (ObjDesc->CommonField.BitLength == AccessBitWidth)) 770 { 771 Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ); 772 return_ACPI_STATUS (Status); 773 } 774 775/* TBD: Move to common setup code */ 776 777 /* Field algorithm is limited to sizeof(UINT64), truncate if needed */ 778 779 if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 780 { 781 ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 782 AccessBitWidth = sizeof (UINT64) * 8; 783 } 784 785 /* Compute the number of datums (access width data items) */ 786 787 DatumCount = ACPI_ROUND_UP_TO ( 788 ObjDesc->CommonField.BitLength, AccessBitWidth); 789 790 FieldDatumCount = ACPI_ROUND_UP_TO ( 791 ObjDesc->CommonField.BitLength + 792 ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); 793 794 /* Priming read from the field */ 795 796 Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); 797 if (ACPI_FAILURE (Status)) 798 { 799 return_ACPI_STATUS (Status); 800 } 801 MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 802 803 /* Read the rest of the field */ 804 805 for (i = 1; i < FieldDatumCount; i++) 806 { 807 /* Get next input datum from the field */ 808 809 FieldOffset += ObjDesc->CommonField.AccessByteWidth; 810 Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, 811 &RawDatum, ACPI_READ); 812 if (ACPI_FAILURE (Status)) 813 { 814 return_ACPI_STATUS (Status); 815 } 816 817 /* 818 * Merge with previous datum if necessary. 819 * 820 * Note: Before the shift, check if the shift value will be larger than 821 * the integer size. If so, there is no need to perform the operation. 822 * This avoids the differences in behavior between different compilers 823 * concerning shift values larger than the target data width. 824 */ 825 if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset < 826 ACPI_INTEGER_BIT_SIZE) 827 { 828 MergedDatum |= RawDatum << 829 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 830 } 831 832 if (i == DatumCount) 833 { 834 break; 835 } 836 837 /* Write merged datum to target buffer */ 838 839 ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 840 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 841 BufferLength - BufferOffset)); 842 843 BufferOffset += ObjDesc->CommonField.AccessByteWidth; 844 MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 845 } 846 847 /* Mask off any extra bits in the last datum */ 848 849 BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth; 850 if (BufferTailBits) 851 { 852 MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 853 } 854 855 /* Write the last datum to the buffer */ 856 857 ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 858 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 859 BufferLength - BufferOffset)); 860 861 return_ACPI_STATUS (AE_OK); 862} 863 864 865/******************************************************************************* 866 * 867 * FUNCTION: AcpiExInsertIntoField 868 * 869 * PARAMETERS: ObjDesc - Field to be written 870 * Buffer - Data to be written 871 * BufferLength - Length of Buffer 872 * 873 * RETURN: Status 874 * 875 * DESCRIPTION: Store the Buffer contents into the given field 876 * 877 ******************************************************************************/ 878 879ACPI_STATUS 880AcpiExInsertIntoField ( 881 ACPI_OPERAND_OBJECT *ObjDesc, 882 void *Buffer, 883 UINT32 BufferLength) 884{ 885 void *NewBuffer; 886 ACPI_STATUS Status; 887 UINT64 Mask; 888 UINT64 WidthMask; 889 UINT64 MergedDatum; 890 UINT64 RawDatum = 0; 891 UINT32 FieldOffset = 0; 892 UINT32 BufferOffset = 0; 893 UINT32 BufferTailBits; 894 UINT32 DatumCount; 895 UINT32 FieldDatumCount; 896 UINT32 AccessBitWidth; 897 UINT32 RequiredLength; 898 UINT32 i; 899 900 901 ACPI_FUNCTION_TRACE (ExInsertIntoField); 902 903 904 /* Validate input buffer */ 905 906 NewBuffer = NULL; 907 RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( 908 ObjDesc->CommonField.BitLength); 909 /* 910 * We must have a buffer that is at least as long as the field 911 * we are writing to. This is because individual fields are 912 * indivisible and partial writes are not supported -- as per 913 * the ACPI specification. 914 */ 915 if (BufferLength < RequiredLength) 916 { 917 /* We need to create a new buffer */ 918 919 NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); 920 if (!NewBuffer) 921 { 922 return_ACPI_STATUS (AE_NO_MEMORY); 923 } 924 925 /* 926 * Copy the original data to the new buffer, starting 927 * at Byte zero. All unused (upper) bytes of the 928 * buffer will be 0. 929 */ 930 ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength); 931 Buffer = NewBuffer; 932 BufferLength = RequiredLength; 933 } 934 935/* TBD: Move to common setup code */ 936 937 /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */ 938 if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 939 { 940 ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 941 } 942 943 AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 944 945 /* 946 * Create the bitmasks used for bit insertion. 947 * Note: This if/else is used to bypass compiler differences with the 948 * shift operator 949 */ 950 if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE) 951 { 952 WidthMask = ACPI_UINT64_MAX; 953 } 954 else 955 { 956 WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth); 957 } 958 959 Mask = WidthMask & 960 ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); 961 962 /* Compute the number of datums (access width data items) */ 963 964 DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, 965 AccessBitWidth); 966 967 FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + 968 ObjDesc->CommonField.StartFieldBitOffset, 969 AccessBitWidth); 970 971 /* Get initial Datum from the input buffer */ 972 973 ACPI_MEMCPY (&RawDatum, Buffer, 974 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 975 BufferLength - BufferOffset)); 976 977 MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 978 979 /* Write the entire field */ 980 981 for (i = 1; i < FieldDatumCount; i++) 982 { 983 /* Write merged datum to the target field */ 984 985 MergedDatum &= Mask; 986 Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, 987 MergedDatum, FieldOffset); 988 if (ACPI_FAILURE (Status)) 989 { 990 goto Exit; 991 } 992 993 FieldOffset += ObjDesc->CommonField.AccessByteWidth; 994 995 /* 996 * Start new output datum by merging with previous input datum 997 * if necessary. 998 * 999 * Note: Before the shift, check if the shift value will be larger than 1000 * the integer size. If so, there is no need to perform the operation. 1001 * This avoids the differences in behavior between different compilers 1002 * concerning shift values larger than the target data width. 1003 */ 1004 if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) < 1005 ACPI_INTEGER_BIT_SIZE) 1006 { 1007 MergedDatum = RawDatum >> 1008 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 1009 } 1010 else 1011 { 1012 MergedDatum = 0; 1013 } 1014 1015 Mask = WidthMask; 1016 1017 if (i == DatumCount) 1018 { 1019 break; 1020 } 1021 1022 /* Get the next input datum from the buffer */ 1023 1024 BufferOffset += ObjDesc->CommonField.AccessByteWidth; 1025 ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset, 1026 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 1027 BufferLength - BufferOffset)); 1028 1029 MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 1030 } 1031 1032 /* Mask off any extra bits in the last datum */ 1033 1034 BufferTailBits = (ObjDesc->CommonField.BitLength + 1035 ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth; 1036 if (BufferTailBits) 1037 { 1038 Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 1039 } 1040 1041 /* Write the last datum to the field */ 1042 1043 MergedDatum &= Mask; 1044 Status = AcpiExWriteWithUpdateRule (ObjDesc, 1045 Mask, MergedDatum, FieldOffset); 1046 1047Exit: 1048 /* Free temporary buffer if we used one */ 1049 1050 if (NewBuffer) 1051 { 1052 ACPI_FREE (NewBuffer); 1053 } 1054 return_ACPI_STATUS (Status); 1055} 1056 1057 1058