1 /******************************************************************************
3 * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2016, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
51 #define _COMPONENT ACPI_EXECUTER
52 ACPI_MODULE_NAME ("exfield")
54 /* Local prototypes */
57 AcpiExGetSerialAccessLength (
62 /*******************************************************************************
64 * FUNCTION: AcpiExGetSerialAccessLength
66 * PARAMETERS: AccessorType - The type of the protocol indicated by region
67 * field access attributes
68 * AccessLength - The access length of the region field
70 * RETURN: Decoded access length
72 * DESCRIPTION: This routine returns the length of the GenericSerialBus
75 ******************************************************************************/
78 AcpiExGetSerialAccessLength (
87 case AML_FIELD_ATTRIB_QUICK
:
92 case AML_FIELD_ATTRIB_SEND_RCV
:
93 case AML_FIELD_ATTRIB_BYTE
:
98 case AML_FIELD_ATTRIB_WORD
:
99 case AML_FIELD_ATTRIB_WORD_CALL
:
104 case AML_FIELD_ATTRIB_MULTIBYTE
:
105 case AML_FIELD_ATTRIB_RAW_BYTES
:
106 case AML_FIELD_ATTRIB_RAW_PROCESS
:
108 Length
= AccessLength
;
111 case AML_FIELD_ATTRIB_BLOCK
:
112 case AML_FIELD_ATTRIB_BLOCK_CALL
:
115 Length
= ACPI_GSBUS_BUFFER_SIZE
- 2;
123 /*******************************************************************************
125 * FUNCTION: AcpiExReadDataFromField
127 * PARAMETERS: WalkState - Current execution state
128 * ObjDesc - The named field
129 * RetBufferDesc - Where the return data object is stored
133 * DESCRIPTION: Read from a named field. Returns either an Integer or a
134 * Buffer, depending on the size of the field.
136 ******************************************************************************/
139 AcpiExReadDataFromField (
140 ACPI_WALK_STATE
*WalkState
,
141 ACPI_OPERAND_OBJECT
*ObjDesc
,
142 ACPI_OPERAND_OBJECT
**RetBufferDesc
)
145 ACPI_OPERAND_OBJECT
*BufferDesc
;
152 ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField
, ObjDesc
);
155 /* Parameter validation */
159 return_ACPI_STATUS (AE_AML_NO_OPERAND
);
163 return_ACPI_STATUS (AE_BAD_PARAMETER
);
166 if (ObjDesc
->Common
.Type
== ACPI_TYPE_BUFFER_FIELD
)
169 * If the BufferField arguments have not been previously evaluated,
170 * evaluate them now and save the results.
172 if (!(ObjDesc
->Common
.Flags
& AOPOBJ_DATA_VALID
))
174 Status
= AcpiDsGetBufferFieldArguments (ObjDesc
);
175 if (ACPI_FAILURE (Status
))
177 return_ACPI_STATUS (Status
);
181 else if ((ObjDesc
->Common
.Type
== ACPI_TYPE_LOCAL_REGION_FIELD
) &&
182 (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
== ACPI_ADR_SPACE_SMBUS
||
183 ObjDesc
->Field
.RegionObj
->Region
.SpaceId
== ACPI_ADR_SPACE_GSBUS
||
184 ObjDesc
->Field
.RegionObj
->Region
.SpaceId
== ACPI_ADR_SPACE_IPMI
))
187 * This is an SMBus, GSBus or IPMI read. We must create a buffer to
188 * hold the data and then directly access the region handler.
190 * Note: SMBus and GSBus protocol value is passed in upper 16-bits
193 if (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
==
194 ACPI_ADR_SPACE_SMBUS
)
196 Length
= ACPI_SMBUS_BUFFER_SIZE
;
197 Function
= ACPI_READ
| (ObjDesc
->Field
.Attribute
<< 16);
199 else if (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
==
200 ACPI_ADR_SPACE_GSBUS
)
202 AccessorType
= ObjDesc
->Field
.Attribute
;
203 Length
= AcpiExGetSerialAccessLength (
204 AccessorType
, ObjDesc
->Field
.AccessLength
);
207 * Add additional 2 bytes for the GenericSerialBus data buffer:
209 * Status; (Byte 0 of the data buffer)
210 * Length; (Byte 1 of the data buffer)
211 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
214 Function
= ACPI_READ
| (AccessorType
<< 16);
218 Length
= ACPI_IPMI_BUFFER_SIZE
;
219 Function
= ACPI_READ
;
222 BufferDesc
= AcpiUtCreateBufferObject (Length
);
225 return_ACPI_STATUS (AE_NO_MEMORY
);
228 /* Lock entire transaction if requested */
230 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
232 /* Call the region handler for the read */
234 Status
= AcpiExAccessRegion (ObjDesc
, 0,
235 ACPI_CAST_PTR (UINT64
, BufferDesc
->Buffer
.Pointer
), Function
);
237 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
242 * Allocate a buffer for the contents of the field.
244 * If the field is larger than the current integer width, create
245 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
246 * the use of arithmetic operators on the returned value if the
247 * field size is equal or smaller than an Integer.
249 * Note: Field.length is in bits.
251 Length
= (ACPI_SIZE
) ACPI_ROUND_BITS_UP_TO_BYTES (
252 ObjDesc
->Field
.BitLength
);
254 if (Length
> AcpiGbl_IntegerByteWidth
)
256 /* Field is too large for an Integer, create a Buffer instead */
258 BufferDesc
= AcpiUtCreateBufferObject (Length
);
261 return_ACPI_STATUS (AE_NO_MEMORY
);
263 Buffer
= BufferDesc
->Buffer
.Pointer
;
267 /* Field will fit within an Integer (normal case) */
269 BufferDesc
= AcpiUtCreateIntegerObject ((UINT64
) 0);
272 return_ACPI_STATUS (AE_NO_MEMORY
);
275 Length
= AcpiGbl_IntegerByteWidth
;
276 Buffer
= &BufferDesc
->Integer
.Value
;
279 if ((ObjDesc
->Common
.Type
== ACPI_TYPE_LOCAL_REGION_FIELD
) &&
280 (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
== ACPI_ADR_SPACE_GPIO
))
283 * For GPIO (GeneralPurposeIo), the Address will be the bit offset
284 * from the previous Connection() operator, making it effectively a
285 * pin number index. The BitLength is the length of the field, which
286 * is thus the number of pins.
288 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
289 "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
290 ObjDesc
->Field
.PinNumberIndex
, ObjDesc
->Field
.BitLength
));
292 /* Lock entire transaction if requested */
294 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
296 /* Perform the write */
298 Status
= AcpiExAccessRegion (
299 ObjDesc
, 0, (UINT64
*) Buffer
, ACPI_READ
);
301 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
302 if (ACPI_FAILURE (Status
))
304 AcpiUtRemoveReference (BufferDesc
);
308 *RetBufferDesc
= BufferDesc
;
310 return_ACPI_STATUS (Status
);
313 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
314 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
315 ObjDesc
, ObjDesc
->Common
.Type
, Buffer
, (UINT32
) Length
));
316 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
317 "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
318 ObjDesc
->CommonField
.BitLength
,
319 ObjDesc
->CommonField
.StartFieldBitOffset
,
320 ObjDesc
->CommonField
.BaseByteOffset
));
322 /* Lock entire transaction if requested */
324 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
326 /* Read from the field */
328 Status
= AcpiExExtractFromField (ObjDesc
, Buffer
, (UINT32
) Length
);
329 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
333 if (ACPI_FAILURE (Status
))
335 AcpiUtRemoveReference (BufferDesc
);
339 *RetBufferDesc
= BufferDesc
;
342 return_ACPI_STATUS (Status
);
346 /*******************************************************************************
348 * FUNCTION: AcpiExWriteDataToField
350 * PARAMETERS: SourceDesc - Contains data to write
351 * ObjDesc - The named field
352 * ResultDesc - Where the return value is returned, if any
356 * DESCRIPTION: Write to a named field
358 ******************************************************************************/
361 AcpiExWriteDataToField (
362 ACPI_OPERAND_OBJECT
*SourceDesc
,
363 ACPI_OPERAND_OBJECT
*ObjDesc
,
364 ACPI_OPERAND_OBJECT
**ResultDesc
)
369 ACPI_OPERAND_OBJECT
*BufferDesc
;
374 ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField
, ObjDesc
);
377 /* Parameter validation */
379 if (!SourceDesc
|| !ObjDesc
)
381 return_ACPI_STATUS (AE_AML_NO_OPERAND
);
384 if (ObjDesc
->Common
.Type
== ACPI_TYPE_BUFFER_FIELD
)
387 * If the BufferField arguments have not been previously evaluated,
388 * evaluate them now and save the results.
390 if (!(ObjDesc
->Common
.Flags
& AOPOBJ_DATA_VALID
))
392 Status
= AcpiDsGetBufferFieldArguments (ObjDesc
);
393 if (ACPI_FAILURE (Status
))
395 return_ACPI_STATUS (Status
);
399 else if ((ObjDesc
->Common
.Type
== ACPI_TYPE_LOCAL_REGION_FIELD
) &&
400 (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
== ACPI_ADR_SPACE_SMBUS
||
401 ObjDesc
->Field
.RegionObj
->Region
.SpaceId
== ACPI_ADR_SPACE_GSBUS
||
402 ObjDesc
->Field
.RegionObj
->Region
.SpaceId
== ACPI_ADR_SPACE_IPMI
))
405 * This is an SMBus, GSBus or IPMI write. We will bypass the entire
406 * field mechanism and handoff the buffer directly to the handler.
407 * For these address spaces, the buffer is bi-directional; on a
408 * write, return data is returned in the same buffer.
410 * Source must be a buffer of sufficient size:
411 * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
412 * ACPI_IPMI_BUFFER_SIZE.
414 * Note: SMBus and GSBus protocol type is passed in upper 16-bits
417 if (SourceDesc
->Common
.Type
!= ACPI_TYPE_BUFFER
)
419 ACPI_ERROR ((AE_INFO
,
420 "SMBus/IPMI/GenericSerialBus write requires "
421 "Buffer, found type %s",
422 AcpiUtGetObjectTypeName (SourceDesc
)));
424 return_ACPI_STATUS (AE_AML_OPERAND_TYPE
);
427 if (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
==
428 ACPI_ADR_SPACE_SMBUS
)
430 Length
= ACPI_SMBUS_BUFFER_SIZE
;
431 Function
= ACPI_WRITE
| (ObjDesc
->Field
.Attribute
<< 16);
433 else if (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
==
434 ACPI_ADR_SPACE_GSBUS
)
436 AccessorType
= ObjDesc
->Field
.Attribute
;
437 Length
= AcpiExGetSerialAccessLength (
438 AccessorType
, ObjDesc
->Field
.AccessLength
);
441 * Add additional 2 bytes for the GenericSerialBus data buffer:
443 * Status; (Byte 0 of the data buffer)
444 * Length; (Byte 1 of the data buffer)
445 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
448 Function
= ACPI_WRITE
| (AccessorType
<< 16);
452 Length
= ACPI_IPMI_BUFFER_SIZE
;
453 Function
= ACPI_WRITE
;
456 if (SourceDesc
->Buffer
.Length
< Length
)
458 ACPI_ERROR ((AE_INFO
,
459 "SMBus/IPMI/GenericSerialBus write requires "
460 "Buffer of length %u, found length %u",
461 Length
, SourceDesc
->Buffer
.Length
));
463 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT
);
466 /* Create the bi-directional buffer */
468 BufferDesc
= AcpiUtCreateBufferObject (Length
);
471 return_ACPI_STATUS (AE_NO_MEMORY
);
474 Buffer
= BufferDesc
->Buffer
.Pointer
;
475 memcpy (Buffer
, SourceDesc
->Buffer
.Pointer
, Length
);
477 /* Lock entire transaction if requested */
479 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
482 * Perform the write (returns status and perhaps data in the
485 Status
= AcpiExAccessRegion (
486 ObjDesc
, 0, (UINT64
*) Buffer
, Function
);
487 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
489 *ResultDesc
= BufferDesc
;
490 return_ACPI_STATUS (Status
);
492 else if ((ObjDesc
->Common
.Type
== ACPI_TYPE_LOCAL_REGION_FIELD
) &&
493 (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
== ACPI_ADR_SPACE_GPIO
))
496 * For GPIO (GeneralPurposeIo), we will bypass the entire field
497 * mechanism and handoff the bit address and bit width directly to
498 * the handler. The Address will be the bit offset
499 * from the previous Connection() operator, making it effectively a
500 * pin number index. The BitLength is the length of the field, which
501 * is thus the number of pins.
503 if (SourceDesc
->Common
.Type
!= ACPI_TYPE_INTEGER
)
505 return_ACPI_STATUS (AE_AML_OPERAND_TYPE
);
508 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
509 "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
510 AcpiUtGetTypeName (SourceDesc
->Common
.Type
),
511 SourceDesc
->Common
.Type
, (UINT32
) SourceDesc
->Integer
.Value
,
512 ObjDesc
->Field
.PinNumberIndex
, ObjDesc
->Field
.BitLength
));
514 Buffer
= &SourceDesc
->Integer
.Value
;
516 /* Lock entire transaction if requested */
518 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
520 /* Perform the write */
522 Status
= AcpiExAccessRegion (
523 ObjDesc
, 0, (UINT64
*) Buffer
, ACPI_WRITE
);
524 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
525 return_ACPI_STATUS (Status
);
528 /* Get a pointer to the data to be written */
530 switch (SourceDesc
->Common
.Type
)
532 case ACPI_TYPE_INTEGER
:
534 Buffer
= &SourceDesc
->Integer
.Value
;
535 Length
= sizeof (SourceDesc
->Integer
.Value
);
538 case ACPI_TYPE_BUFFER
:
540 Buffer
= SourceDesc
->Buffer
.Pointer
;
541 Length
= SourceDesc
->Buffer
.Length
;
544 case ACPI_TYPE_STRING
:
546 Buffer
= SourceDesc
->String
.Pointer
;
547 Length
= SourceDesc
->String
.Length
;
552 return_ACPI_STATUS (AE_AML_OPERAND_TYPE
);
555 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
556 "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
557 SourceDesc
, AcpiUtGetTypeName (SourceDesc
->Common
.Type
),
558 SourceDesc
->Common
.Type
, Buffer
, Length
));
560 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
561 "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
562 ObjDesc
, AcpiUtGetTypeName (ObjDesc
->Common
.Type
),
563 ObjDesc
->Common
.Type
,
564 ObjDesc
->CommonField
.BitLength
,
565 ObjDesc
->CommonField
.StartFieldBitOffset
,
566 ObjDesc
->CommonField
.BaseByteOffset
));
568 /* Lock entire transaction if requested */
570 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
572 /* Write to the field */
574 Status
= AcpiExInsertIntoField (ObjDesc
, Buffer
, Length
);
575 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
577 return_ACPI_STATUS (Status
);