exfield.c revision 217365
167754Smsmith/****************************************************************************** 267754Smsmith * 377424Smsmith * Module Name: exfield - ACPI AML (p-code) execution - field manipulation 467754Smsmith * 567754Smsmith *****************************************************************************/ 667754Smsmith 7217365Sjkim/* 8217365Sjkim * Copyright (C) 2000 - 2011, Intel Corp. 970243Smsmith * All rights reserved. 1067754Smsmith * 11217365Sjkim * Redistribution and use in source and binary forms, with or without 12217365Sjkim * modification, are permitted provided that the following conditions 13217365Sjkim * are met: 14217365Sjkim * 1. Redistributions of source code must retain the above copyright 15217365Sjkim * notice, this list of conditions, and the following disclaimer, 16217365Sjkim * without modification. 17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20217365Sjkim * including a substantially similar Disclaimer requirement for further 21217365Sjkim * binary redistribution. 22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23217365Sjkim * of any contributors may be used to endorse or promote products derived 24217365Sjkim * from this software without specific prior written permission. 2567754Smsmith * 26217365Sjkim * Alternatively, this software may be distributed under the terms of the 27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28217365Sjkim * Software Foundation. 2967754Smsmith * 30217365Sjkim * NO WARRANTY 31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 42217365Sjkim */ 4367754Smsmith 4467754Smsmith 4577424Smsmith#define __EXFIELD_C__ 4667754Smsmith 47193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 48193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 49193341Sjkim#include <contrib/dev/acpica/include/acdispat.h> 50193341Sjkim#include <contrib/dev/acpica/include/acinterp.h> 5167754Smsmith 5267754Smsmith 5377424Smsmith#define _COMPONENT ACPI_EXECUTER 5491116Smsmith ACPI_MODULE_NAME ("exfield") 5567754Smsmith 5667754Smsmith 5767754Smsmith/******************************************************************************* 5867754Smsmith * 5977424Smsmith * FUNCTION: AcpiExReadDataFromField 6067754Smsmith * 6199146Siwasaki * PARAMETERS: WalkState - Current execution state 6299146Siwasaki * ObjDesc - The named field 6387031Smsmith * RetBufferDesc - Where the return data object is stored 6467754Smsmith * 6587031Smsmith * RETURN: Status 6667754Smsmith * 6787031Smsmith * DESCRIPTION: Read from a named field. Returns either an Integer or a 6887031Smsmith * Buffer, depending on the size of the field. 6967754Smsmith * 7067754Smsmith ******************************************************************************/ 7167754Smsmith 7267754SmsmithACPI_STATUS 7377424SmsmithAcpiExReadDataFromField ( 7499146Siwasaki ACPI_WALK_STATE *WalkState, 7567754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 7677424Smsmith ACPI_OPERAND_OBJECT **RetBufferDesc) 7767754Smsmith{ 7877424Smsmith ACPI_STATUS Status; 7977424Smsmith ACPI_OPERAND_OBJECT *BufferDesc; 80114237Snjl ACPI_SIZE Length; 8177424Smsmith void *Buffer; 82197104Sjkim UINT32 Function; 8367754Smsmith 8467754Smsmith 85167802Sjkim ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc); 8667754Smsmith 8767754Smsmith 8867754Smsmith /* Parameter validation */ 8967754Smsmith 9077424Smsmith if (!ObjDesc) 9167754Smsmith { 9267754Smsmith return_ACPI_STATUS (AE_AML_NO_OPERAND); 9367754Smsmith } 94151937Sjkim if (!RetBufferDesc) 95151937Sjkim { 96151937Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 97151937Sjkim } 9867754Smsmith 99193267Sjkim if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) 10087031Smsmith { 10187031Smsmith /* 10287031Smsmith * If the BufferField arguments have not been previously evaluated, 10387031Smsmith * evaluate them now and save the results. 10487031Smsmith */ 10587031Smsmith if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 10687031Smsmith { 10787031Smsmith Status = AcpiDsGetBufferFieldArguments (ObjDesc); 10887031Smsmith if (ACPI_FAILURE (Status)) 10987031Smsmith { 11087031Smsmith return_ACPI_STATUS (Status); 11187031Smsmith } 11287031Smsmith } 11387031Smsmith } 114193267Sjkim else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 115197104Sjkim (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 116197104Sjkim ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) 117107325Siwasaki { 118107325Siwasaki /* 119197104Sjkim * This is an SMBus or IPMI read. We must create a buffer to hold 120197104Sjkim * the data and then directly access the region handler. 121197104Sjkim * 122197104Sjkim * Note: Smbus protocol value is passed in upper 16-bits of Function 123107325Siwasaki */ 124197104Sjkim if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 125197104Sjkim { 126197104Sjkim Length = ACPI_SMBUS_BUFFER_SIZE; 127197104Sjkim Function = ACPI_READ | (ObjDesc->Field.Attribute << 16); 128197104Sjkim } 129197104Sjkim else /* IPMI */ 130197104Sjkim { 131197104Sjkim Length = ACPI_IPMI_BUFFER_SIZE; 132197104Sjkim Function = ACPI_READ; 133197104Sjkim } 134197104Sjkim 135197104Sjkim BufferDesc = AcpiUtCreateBufferObject (Length); 136107325Siwasaki if (!BufferDesc) 137107325Siwasaki { 138107325Siwasaki return_ACPI_STATUS (AE_NO_MEMORY); 139107325Siwasaki } 14087031Smsmith 141107325Siwasaki /* Lock entire transaction if requested */ 142107325Siwasaki 143167802Sjkim AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 144107325Siwasaki 145197104Sjkim /* Call the region handler for the read */ 146197104Sjkim 147114237Snjl Status = AcpiExAccessRegion (ObjDesc, 0, 148202771Sjkim ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), 149197104Sjkim Function); 150167802Sjkim AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 151107325Siwasaki goto Exit; 152107325Siwasaki } 153107325Siwasaki 15467754Smsmith /* 15577424Smsmith * Allocate a buffer for the contents of the field. 15667754Smsmith * 157202771Sjkim * If the field is larger than the current integer width, create 15877424Smsmith * a BUFFER to hold it. Otherwise, use an INTEGER. This allows 15977424Smsmith * the use of arithmetic operators on the returned value if the 16077424Smsmith * field size is equal or smaller than an Integer. 16177424Smsmith * 16277424Smsmith * Note: Field.length is in bits. 16367754Smsmith */ 164114237Snjl Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength); 16599679Siwasaki if (Length > AcpiGbl_IntegerByteWidth) 16667754Smsmith { 16777424Smsmith /* Field is too large for an Integer, create a Buffer instead */ 16867754Smsmith 169107325Siwasaki BufferDesc = AcpiUtCreateBufferObject (Length); 17077424Smsmith if (!BufferDesc) 17177424Smsmith { 17277424Smsmith return_ACPI_STATUS (AE_NO_MEMORY); 17377424Smsmith } 17477424Smsmith Buffer = BufferDesc->Buffer.Pointer; 17567754Smsmith } 17677424Smsmith else 17777424Smsmith { 17877424Smsmith /* Field will fit within an Integer (normal case) */ 17967754Smsmith 180199337Sjkim BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0); 18177424Smsmith if (!BufferDesc) 18277424Smsmith { 18377424Smsmith return_ACPI_STATUS (AE_NO_MEMORY); 18477424Smsmith } 18577424Smsmith 18699679Siwasaki Length = AcpiGbl_IntegerByteWidth; 18777424Smsmith Buffer = &BufferDesc->Integer.Value; 18867754Smsmith } 18967754Smsmith 19099146Siwasaki ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 191123315Snjl "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", 192193267Sjkim ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length)); 19399146Siwasaki ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 194123315Snjl "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", 19587031Smsmith ObjDesc->CommonField.BitLength, 19687031Smsmith ObjDesc->CommonField.StartFieldBitOffset, 19787031Smsmith ObjDesc->CommonField.BaseByteOffset)); 19877424Smsmith 199107325Siwasaki /* Lock entire transaction if requested */ 200107325Siwasaki 201167802Sjkim AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 20277424Smsmith 20387031Smsmith /* Read from the field */ 20467754Smsmith 205114237Snjl Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length); 206167802Sjkim AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 20767754Smsmith 208107325Siwasaki 209107325SiwasakiExit: 21077424Smsmith if (ACPI_FAILURE (Status)) 21177424Smsmith { 21277424Smsmith AcpiUtRemoveReference (BufferDesc); 21377424Smsmith } 214151937Sjkim else 21577424Smsmith { 21677424Smsmith *RetBufferDesc = BufferDesc; 21777424Smsmith } 21877424Smsmith 21977424Smsmith return_ACPI_STATUS (Status); 22067754Smsmith} 22167754Smsmith 22267754Smsmith 22367754Smsmith/******************************************************************************* 22467754Smsmith * 22577424Smsmith * FUNCTION: AcpiExWriteDataToField 22667754Smsmith * 22787031Smsmith * PARAMETERS: SourceDesc - Contains data to write 22887031Smsmith * ObjDesc - The named field 229151937Sjkim * ResultDesc - Where the return value is returned, if any 23067754Smsmith * 23167754Smsmith * RETURN: Status 23267754Smsmith * 23387031Smsmith * DESCRIPTION: Write to a named field 23467754Smsmith * 23567754Smsmith ******************************************************************************/ 23667754Smsmith 23767754SmsmithACPI_STATUS 23877424SmsmithAcpiExWriteDataToField ( 23977424Smsmith ACPI_OPERAND_OBJECT *SourceDesc, 240107325Siwasaki ACPI_OPERAND_OBJECT *ObjDesc, 241107325Siwasaki ACPI_OPERAND_OBJECT **ResultDesc) 24267754Smsmith{ 24377424Smsmith ACPI_STATUS Status; 24477424Smsmith UINT32 Length; 24577424Smsmith void *Buffer; 246107325Siwasaki ACPI_OPERAND_OBJECT *BufferDesc; 247197104Sjkim UINT32 Function; 24867754Smsmith 24967754Smsmith 250167802Sjkim ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc); 25167754Smsmith 25267754Smsmith 25371867Smsmith /* Parameter validation */ 25471867Smsmith 25577424Smsmith if (!SourceDesc || !ObjDesc) 25667754Smsmith { 25777424Smsmith return_ACPI_STATUS (AE_AML_NO_OPERAND); 25867754Smsmith } 25967754Smsmith 260193267Sjkim if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) 26187031Smsmith { 26287031Smsmith /* 26387031Smsmith * If the BufferField arguments have not been previously evaluated, 26487031Smsmith * evaluate them now and save the results. 26587031Smsmith */ 26687031Smsmith if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 26787031Smsmith { 26887031Smsmith Status = AcpiDsGetBufferFieldArguments (ObjDesc); 26987031Smsmith if (ACPI_FAILURE (Status)) 27087031Smsmith { 27187031Smsmith return_ACPI_STATUS (Status); 27287031Smsmith } 27387031Smsmith } 27487031Smsmith } 275193267Sjkim else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 276197104Sjkim (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 277197104Sjkim ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) 278107325Siwasaki { 279107325Siwasaki /* 280197104Sjkim * This is an SMBus or IPMI write. We will bypass the entire field 281197104Sjkim * mechanism and handoff the buffer directly to the handler. For 282197104Sjkim * these address spaces, the buffer is bi-directional; on a write, 283197104Sjkim * return data is returned in the same buffer. 284107325Siwasaki * 285197104Sjkim * Source must be a buffer of sufficient size: 286197104Sjkim * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE. 287197104Sjkim * 288197104Sjkim * Note: SMBus protocol type is passed in upper 16-bits of Function 289107325Siwasaki */ 290193267Sjkim if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER) 291107325Siwasaki { 292197104Sjkim ACPI_ERROR ((AE_INFO, 293197104Sjkim "SMBus or IPMI write requires Buffer, found type %s", 294107325Siwasaki AcpiUtGetObjectTypeName (SourceDesc))); 295151937Sjkim 296107325Siwasaki return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 297107325Siwasaki } 29867754Smsmith 299197104Sjkim if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 300107325Siwasaki { 301197104Sjkim Length = ACPI_SMBUS_BUFFER_SIZE; 302197104Sjkim Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16); 303197104Sjkim } 304197104Sjkim else /* IPMI */ 305197104Sjkim { 306197104Sjkim Length = ACPI_IPMI_BUFFER_SIZE; 307197104Sjkim Function = ACPI_WRITE; 308197104Sjkim } 309197104Sjkim 310197104Sjkim if (SourceDesc->Buffer.Length < Length) 311197104Sjkim { 312167802Sjkim ACPI_ERROR ((AE_INFO, 313204773Sjkim "SMBus or IPMI write requires Buffer of length %u, found length %u", 314197104Sjkim Length, SourceDesc->Buffer.Length)); 315151937Sjkim 316107325Siwasaki return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); 317107325Siwasaki } 318107325Siwasaki 319197104Sjkim /* Create the bi-directional buffer */ 320197104Sjkim 321197104Sjkim BufferDesc = AcpiUtCreateBufferObject (Length); 322107325Siwasaki if (!BufferDesc) 323107325Siwasaki { 324107325Siwasaki return_ACPI_STATUS (AE_NO_MEMORY); 325107325Siwasaki } 326107325Siwasaki 327107325Siwasaki Buffer = BufferDesc->Buffer.Pointer; 328197104Sjkim ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length); 329107325Siwasaki 330107325Siwasaki /* Lock entire transaction if requested */ 331107325Siwasaki 332167802Sjkim AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 333107325Siwasaki 334114237Snjl /* 335151937Sjkim * Perform the write (returns status and perhaps data in the 336151937Sjkim * same buffer) 337107325Siwasaki */ 338114237Snjl Status = AcpiExAccessRegion (ObjDesc, 0, 339202771Sjkim (UINT64 *) Buffer, Function); 340167802Sjkim AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 341107325Siwasaki 342107325Siwasaki *ResultDesc = BufferDesc; 343107325Siwasaki return_ACPI_STATUS (Status); 344107325Siwasaki } 345107325Siwasaki 346151937Sjkim /* Get a pointer to the data to be written */ 347151937Sjkim 348193267Sjkim switch (SourceDesc->Common.Type) 34967754Smsmith { 35077424Smsmith case ACPI_TYPE_INTEGER: 35177424Smsmith Buffer = &SourceDesc->Integer.Value; 35277424Smsmith Length = sizeof (SourceDesc->Integer.Value); 35377424Smsmith break; 35477424Smsmith 35577424Smsmith case ACPI_TYPE_BUFFER: 35677424Smsmith Buffer = SourceDesc->Buffer.Pointer; 35777424Smsmith Length = SourceDesc->Buffer.Length; 35877424Smsmith break; 35977424Smsmith 36077424Smsmith case ACPI_TYPE_STRING: 36177424Smsmith Buffer = SourceDesc->String.Pointer; 36277424Smsmith Length = SourceDesc->String.Length; 36377424Smsmith break; 36477424Smsmith 36577424Smsmith default: 36677424Smsmith return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 36767754Smsmith } 36867754Smsmith 36999146Siwasaki ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 370123315Snjl "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", 371193267Sjkim SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type), 372193267Sjkim SourceDesc->Common.Type, Buffer, Length)); 373151937Sjkim 37499146Siwasaki ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 375123315Snjl "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", 376193267Sjkim ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type), 377193267Sjkim ObjDesc->Common.Type, 37887031Smsmith ObjDesc->CommonField.BitLength, 37987031Smsmith ObjDesc->CommonField.StartFieldBitOffset, 38087031Smsmith ObjDesc->CommonField.BaseByteOffset)); 38167754Smsmith 382107325Siwasaki /* Lock entire transaction if requested */ 383107325Siwasaki 384167802Sjkim AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 38577424Smsmith 386107325Siwasaki /* Write to the field */ 387107325Siwasaki 38887031Smsmith Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length); 389167802Sjkim AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 39067754Smsmith 39177424Smsmith return_ACPI_STATUS (Status); 39277424Smsmith} 39377424Smsmith 39477424Smsmith 395