exfield.c revision 228110
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 || 116228110Sjkim ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS || 117197104Sjkim ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) 118107325Siwasaki { 119107325Siwasaki /* 120228110Sjkim * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold 121197104Sjkim * the data and then directly access the region handler. 122197104Sjkim * 123228110Sjkim * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function 124107325Siwasaki */ 125197104Sjkim if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 126197104Sjkim { 127197104Sjkim Length = ACPI_SMBUS_BUFFER_SIZE; 128197104Sjkim Function = ACPI_READ | (ObjDesc->Field.Attribute << 16); 129197104Sjkim } 130228110Sjkim else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) 131228110Sjkim { 132228110Sjkim Length = ACPI_GSBUS_BUFFER_SIZE; 133228110Sjkim Function = ACPI_READ | (ObjDesc->Field.Attribute << 16); 134228110Sjkim } 135197104Sjkim else /* IPMI */ 136197104Sjkim { 137197104Sjkim Length = ACPI_IPMI_BUFFER_SIZE; 138197104Sjkim Function = ACPI_READ; 139197104Sjkim } 140197104Sjkim 141197104Sjkim BufferDesc = AcpiUtCreateBufferObject (Length); 142107325Siwasaki if (!BufferDesc) 143107325Siwasaki { 144107325Siwasaki return_ACPI_STATUS (AE_NO_MEMORY); 145107325Siwasaki } 14687031Smsmith 147107325Siwasaki /* Lock entire transaction if requested */ 148107325Siwasaki 149167802Sjkim AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 150107325Siwasaki 151197104Sjkim /* Call the region handler for the read */ 152197104Sjkim 153114237Snjl Status = AcpiExAccessRegion (ObjDesc, 0, 154202771Sjkim ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), 155197104Sjkim Function); 156167802Sjkim AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 157107325Siwasaki goto Exit; 158107325Siwasaki } 159107325Siwasaki 16067754Smsmith /* 16177424Smsmith * Allocate a buffer for the contents of the field. 16267754Smsmith * 163202771Sjkim * If the field is larger than the current integer width, create 16477424Smsmith * a BUFFER to hold it. Otherwise, use an INTEGER. This allows 16577424Smsmith * the use of arithmetic operators on the returned value if the 16677424Smsmith * field size is equal or smaller than an Integer. 16777424Smsmith * 16877424Smsmith * Note: Field.length is in bits. 16967754Smsmith */ 170114237Snjl Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength); 17199679Siwasaki if (Length > AcpiGbl_IntegerByteWidth) 17267754Smsmith { 17377424Smsmith /* Field is too large for an Integer, create a Buffer instead */ 17467754Smsmith 175107325Siwasaki BufferDesc = AcpiUtCreateBufferObject (Length); 17677424Smsmith if (!BufferDesc) 17777424Smsmith { 17877424Smsmith return_ACPI_STATUS (AE_NO_MEMORY); 17977424Smsmith } 18077424Smsmith Buffer = BufferDesc->Buffer.Pointer; 18167754Smsmith } 18277424Smsmith else 18377424Smsmith { 18477424Smsmith /* Field will fit within an Integer (normal case) */ 18567754Smsmith 186199337Sjkim BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0); 18777424Smsmith if (!BufferDesc) 18877424Smsmith { 18977424Smsmith return_ACPI_STATUS (AE_NO_MEMORY); 19077424Smsmith } 19177424Smsmith 19299679Siwasaki Length = AcpiGbl_IntegerByteWidth; 19377424Smsmith Buffer = &BufferDesc->Integer.Value; 19467754Smsmith } 19567754Smsmith 19699146Siwasaki ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 197123315Snjl "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", 198193267Sjkim ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length)); 19999146Siwasaki ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 200123315Snjl "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", 20187031Smsmith ObjDesc->CommonField.BitLength, 20287031Smsmith ObjDesc->CommonField.StartFieldBitOffset, 20387031Smsmith ObjDesc->CommonField.BaseByteOffset)); 20477424Smsmith 205107325Siwasaki /* Lock entire transaction if requested */ 206107325Siwasaki 207167802Sjkim AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 20877424Smsmith 20987031Smsmith /* Read from the field */ 21067754Smsmith 211114237Snjl Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length); 212167802Sjkim AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 21367754Smsmith 214107325Siwasaki 215107325SiwasakiExit: 21677424Smsmith if (ACPI_FAILURE (Status)) 21777424Smsmith { 21877424Smsmith AcpiUtRemoveReference (BufferDesc); 21977424Smsmith } 220151937Sjkim else 22177424Smsmith { 22277424Smsmith *RetBufferDesc = BufferDesc; 22377424Smsmith } 22477424Smsmith 22577424Smsmith return_ACPI_STATUS (Status); 22667754Smsmith} 22767754Smsmith 22867754Smsmith 22967754Smsmith/******************************************************************************* 23067754Smsmith * 23177424Smsmith * FUNCTION: AcpiExWriteDataToField 23267754Smsmith * 23387031Smsmith * PARAMETERS: SourceDesc - Contains data to write 23487031Smsmith * ObjDesc - The named field 235151937Sjkim * ResultDesc - Where the return value is returned, if any 23667754Smsmith * 23767754Smsmith * RETURN: Status 23867754Smsmith * 23987031Smsmith * DESCRIPTION: Write to a named field 24067754Smsmith * 24167754Smsmith ******************************************************************************/ 24267754Smsmith 24367754SmsmithACPI_STATUS 24477424SmsmithAcpiExWriteDataToField ( 24577424Smsmith ACPI_OPERAND_OBJECT *SourceDesc, 246107325Siwasaki ACPI_OPERAND_OBJECT *ObjDesc, 247107325Siwasaki ACPI_OPERAND_OBJECT **ResultDesc) 24867754Smsmith{ 24977424Smsmith ACPI_STATUS Status; 25077424Smsmith UINT32 Length; 25177424Smsmith void *Buffer; 252107325Siwasaki ACPI_OPERAND_OBJECT *BufferDesc; 253197104Sjkim UINT32 Function; 25467754Smsmith 25567754Smsmith 256167802Sjkim ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc); 25767754Smsmith 25867754Smsmith 25971867Smsmith /* Parameter validation */ 26071867Smsmith 26177424Smsmith if (!SourceDesc || !ObjDesc) 26267754Smsmith { 26377424Smsmith return_ACPI_STATUS (AE_AML_NO_OPERAND); 26467754Smsmith } 26567754Smsmith 266193267Sjkim if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) 26787031Smsmith { 26887031Smsmith /* 26987031Smsmith * If the BufferField arguments have not been previously evaluated, 27087031Smsmith * evaluate them now and save the results. 27187031Smsmith */ 27287031Smsmith if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 27387031Smsmith { 27487031Smsmith Status = AcpiDsGetBufferFieldArguments (ObjDesc); 27587031Smsmith if (ACPI_FAILURE (Status)) 27687031Smsmith { 27787031Smsmith return_ACPI_STATUS (Status); 27887031Smsmith } 27987031Smsmith } 28087031Smsmith } 281193267Sjkim else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 282197104Sjkim (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 283228110Sjkim ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS || 284197104Sjkim ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) 285107325Siwasaki { 286107325Siwasaki /* 287228110Sjkim * This is an SMBus, GSBus or IPMI write. We will bypass the entire field 288197104Sjkim * mechanism and handoff the buffer directly to the handler. For 289197104Sjkim * these address spaces, the buffer is bi-directional; on a write, 290197104Sjkim * return data is returned in the same buffer. 291107325Siwasaki * 292197104Sjkim * Source must be a buffer of sufficient size: 293228110Sjkim * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. 294197104Sjkim * 295228110Sjkim * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function 296107325Siwasaki */ 297193267Sjkim if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER) 298107325Siwasaki { 299197104Sjkim ACPI_ERROR ((AE_INFO, 300228110Sjkim "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", 301107325Siwasaki AcpiUtGetObjectTypeName (SourceDesc))); 302151937Sjkim 303107325Siwasaki return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 304107325Siwasaki } 30567754Smsmith 306197104Sjkim if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 307107325Siwasaki { 308197104Sjkim Length = ACPI_SMBUS_BUFFER_SIZE; 309197104Sjkim Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16); 310197104Sjkim } 311228110Sjkim else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) 312228110Sjkim { 313228110Sjkim Length = ACPI_GSBUS_BUFFER_SIZE; 314228110Sjkim Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16); 315228110Sjkim } 316197104Sjkim else /* IPMI */ 317197104Sjkim { 318197104Sjkim Length = ACPI_IPMI_BUFFER_SIZE; 319197104Sjkim Function = ACPI_WRITE; 320197104Sjkim } 321197104Sjkim 322197104Sjkim if (SourceDesc->Buffer.Length < Length) 323197104Sjkim { 324167802Sjkim ACPI_ERROR ((AE_INFO, 325228110Sjkim "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", 326197104Sjkim Length, SourceDesc->Buffer.Length)); 327151937Sjkim 328107325Siwasaki return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); 329107325Siwasaki } 330107325Siwasaki 331197104Sjkim /* Create the bi-directional buffer */ 332197104Sjkim 333197104Sjkim BufferDesc = AcpiUtCreateBufferObject (Length); 334107325Siwasaki if (!BufferDesc) 335107325Siwasaki { 336107325Siwasaki return_ACPI_STATUS (AE_NO_MEMORY); 337107325Siwasaki } 338107325Siwasaki 339107325Siwasaki Buffer = BufferDesc->Buffer.Pointer; 340197104Sjkim ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length); 341107325Siwasaki 342107325Siwasaki /* Lock entire transaction if requested */ 343107325Siwasaki 344167802Sjkim AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 345107325Siwasaki 346114237Snjl /* 347151937Sjkim * Perform the write (returns status and perhaps data in the 348151937Sjkim * same buffer) 349107325Siwasaki */ 350114237Snjl Status = AcpiExAccessRegion (ObjDesc, 0, 351202771Sjkim (UINT64 *) Buffer, Function); 352167802Sjkim AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 353107325Siwasaki 354107325Siwasaki *ResultDesc = BufferDesc; 355107325Siwasaki return_ACPI_STATUS (Status); 356107325Siwasaki } 357107325Siwasaki 358151937Sjkim /* Get a pointer to the data to be written */ 359151937Sjkim 360193267Sjkim switch (SourceDesc->Common.Type) 36167754Smsmith { 36277424Smsmith case ACPI_TYPE_INTEGER: 36377424Smsmith Buffer = &SourceDesc->Integer.Value; 36477424Smsmith Length = sizeof (SourceDesc->Integer.Value); 36577424Smsmith break; 36677424Smsmith 36777424Smsmith case ACPI_TYPE_BUFFER: 36877424Smsmith Buffer = SourceDesc->Buffer.Pointer; 36977424Smsmith Length = SourceDesc->Buffer.Length; 37077424Smsmith break; 37177424Smsmith 37277424Smsmith case ACPI_TYPE_STRING: 37377424Smsmith Buffer = SourceDesc->String.Pointer; 37477424Smsmith Length = SourceDesc->String.Length; 37577424Smsmith break; 37677424Smsmith 37777424Smsmith default: 37877424Smsmith return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 37967754Smsmith } 38067754Smsmith 38199146Siwasaki ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 382123315Snjl "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", 383193267Sjkim SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type), 384193267Sjkim SourceDesc->Common.Type, Buffer, Length)); 385151937Sjkim 38699146Siwasaki ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 387123315Snjl "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", 388193267Sjkim ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type), 389193267Sjkim ObjDesc->Common.Type, 39087031Smsmith ObjDesc->CommonField.BitLength, 39187031Smsmith ObjDesc->CommonField.StartFieldBitOffset, 39287031Smsmith ObjDesc->CommonField.BaseByteOffset)); 39367754Smsmith 394107325Siwasaki /* Lock entire transaction if requested */ 395107325Siwasaki 396167802Sjkim AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 39777424Smsmith 398107325Siwasaki /* Write to the field */ 399107325Siwasaki 40087031Smsmith Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length); 401167802Sjkim AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 40267754Smsmith 40377424Smsmith return_ACPI_STATUS (Status); 40477424Smsmith} 40577424Smsmith 40677424Smsmith 407