1 /****************************************************************************** 2 * 3 * Module Name: exfield - ACPI AML (p-code) execution - field manipulation 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 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. 25 * 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. 29 * 30 * NO WARRANTY 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. 42 */ 43 44 #define __EXFIELD_C__ 45 46 #include <contrib/dev/acpica/include/acpi.h> 47 #include <contrib/dev/acpica/include/accommon.h> 48 #include <contrib/dev/acpica/include/acdispat.h> 49 #include <contrib/dev/acpica/include/acinterp.h> 50 #include <contrib/dev/acpica/include/amlcode.h> 51 52 53 #define _COMPONENT ACPI_EXECUTER 54 ACPI_MODULE_NAME ("exfield") 55 56 /* Local prototypes */ 57 58 static UINT32 59 AcpiExGetSerialAccessLength ( 60 UINT32 AccessorType, 61 UINT32 AccessLength); 62 63 64 /******************************************************************************* 65 * 66 * FUNCTION: AcpiExGetSerialAccessLength 67 * 68 * PARAMETERS: AccessorType - The type of the protocol indicated by region 69 * field access attributes 70 * AccessLength - The access length of the region field 71 * 72 * RETURN: Decoded access length 73 * 74 * DESCRIPTION: This routine returns the length of the GenericSerialBus 75 * protocol bytes 76 * 77 ******************************************************************************/ 78 79 static UINT32 80 AcpiExGetSerialAccessLength ( 81 UINT32 AccessorType, 82 UINT32 AccessLength) 83 { 84 UINT32 Length; 85 86 87 switch (AccessorType) 88 { 89 case AML_FIELD_ATTRIB_QUICK: 90 91 Length = 0; 92 break; 93 94 case AML_FIELD_ATTRIB_SEND_RCV: 95 case AML_FIELD_ATTRIB_BYTE: 96 97 Length = 1; 98 break; 99 100 case AML_FIELD_ATTRIB_WORD: 101 case AML_FIELD_ATTRIB_WORD_CALL: 102 103 Length = 2; 104 break; 105 106 case AML_FIELD_ATTRIB_MULTIBYTE: 107 case AML_FIELD_ATTRIB_RAW_BYTES: 108 case AML_FIELD_ATTRIB_RAW_PROCESS: 109 110 Length = AccessLength; 111 break; 112 113 case AML_FIELD_ATTRIB_BLOCK: 114 case AML_FIELD_ATTRIB_BLOCK_CALL: 115 default: 116 117 Length = ACPI_GSBUS_BUFFER_SIZE - 2; 118 break; 119 } 120 121 return (Length); 122 } 123 124 125 /******************************************************************************* 126 * 127 * FUNCTION: AcpiExReadDataFromField 128 * 129 * PARAMETERS: WalkState - Current execution state 130 * ObjDesc - The named field 131 * RetBufferDesc - Where the return data object is stored 132 * 133 * RETURN: Status 134 * 135 * DESCRIPTION: Read from a named field. Returns either an Integer or a 136 * Buffer, depending on the size of the field. 137 * 138 ******************************************************************************/ 139 140 ACPI_STATUS 141 AcpiExReadDataFromField ( 142 ACPI_WALK_STATE *WalkState, 143 ACPI_OPERAND_OBJECT *ObjDesc, 144 ACPI_OPERAND_OBJECT **RetBufferDesc) 145 { 146 ACPI_STATUS Status; 147 ACPI_OPERAND_OBJECT *BufferDesc; 148 ACPI_SIZE Length; 149 void *Buffer; 150 UINT32 Function; 151 UINT16 AccessorType; 152 153 154 ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc); 155 156 157 /* Parameter validation */ 158 159 if (!ObjDesc) 160 { 161 return_ACPI_STATUS (AE_AML_NO_OPERAND); 162 } 163 if (!RetBufferDesc) 164 { 165 return_ACPI_STATUS (AE_BAD_PARAMETER); 166 } 167 168 if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) 169 { 170 /* 171 * If the BufferField arguments have not been previously evaluated, 172 * evaluate them now and save the results. 173 */ 174 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 175 { 176 Status = AcpiDsGetBufferFieldArguments (ObjDesc); 177 if (ACPI_FAILURE (Status)) 178 { 179 return_ACPI_STATUS (Status); 180 } 181 } 182 } 183 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 184 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 185 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS || 186 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) 187 { 188 /* 189 * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold 190 * the data and then directly access the region handler. 191 * 192 * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function 193 */ 194 if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 195 { 196 Length = ACPI_SMBUS_BUFFER_SIZE; 197 Function = ACPI_READ | (ObjDesc->Field.Attribute << 16); 198 } 199 else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) 200 { 201 AccessorType = ObjDesc->Field.Attribute; 202 Length = AcpiExGetSerialAccessLength (AccessorType, 203 ObjDesc->Field.AccessLength); 204 205 /* 206 * Add additional 2 bytes for the GenericSerialBus data buffer: 207 * 208 * Status; (Byte 0 of the data buffer) 209 * Length; (Byte 1 of the data buffer) 210 * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) 211 */ 212 Length += 2; 213 Function = ACPI_READ | (AccessorType << 16); 214 } 215 else /* IPMI */ 216 { 217 Length = ACPI_IPMI_BUFFER_SIZE; 218 Function = ACPI_READ; 219 } 220 221 BufferDesc = AcpiUtCreateBufferObject (Length); 222 if (!BufferDesc) 223 { 224 return_ACPI_STATUS (AE_NO_MEMORY); 225 } 226 227 /* Lock entire transaction if requested */ 228 229 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 230 231 /* Call the region handler for the read */ 232 233 Status = AcpiExAccessRegion (ObjDesc, 0, 234 ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), 235 Function); 236 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 237 goto Exit; 238 } 239 240 /* 241 * Allocate a buffer for the contents of the field. 242 * 243 * If the field is larger than the current integer width, create 244 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows 245 * the use of arithmetic operators on the returned value if the 246 * field size is equal or smaller than an Integer. 247 * 248 * Note: Field.length is in bits. 249 */ 250 Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength); 251 if (Length > AcpiGbl_IntegerByteWidth) 252 { 253 /* Field is too large for an Integer, create a Buffer instead */ 254 255 BufferDesc = AcpiUtCreateBufferObject (Length); 256 if (!BufferDesc) 257 { 258 return_ACPI_STATUS (AE_NO_MEMORY); 259 } 260 Buffer = BufferDesc->Buffer.Pointer; 261 } 262 else 263 { 264 /* Field will fit within an Integer (normal case) */ 265 266 BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0); 267 if (!BufferDesc) 268 { 269 return_ACPI_STATUS (AE_NO_MEMORY); 270 } 271 272 Length = AcpiGbl_IntegerByteWidth; 273 Buffer = &BufferDesc->Integer.Value; 274 } 275 276 if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 277 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO)) 278 { 279 /* 280 * For GPIO (GeneralPurposeIo), the Address will be the bit offset 281 * from the previous Connection() operator, making it effectively a 282 * pin number index. The BitLength is the length of the field, which 283 * is thus the number of pins. 284 */ 285 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 286 "GPIO FieldRead [FROM]: Pin %u Bits %u\n", 287 ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength)); 288 289 /* Lock entire transaction if requested */ 290 291 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 292 293 /* Perform the write */ 294 295 Status = AcpiExAccessRegion (ObjDesc, 0, 296 (UINT64 *) Buffer, ACPI_READ); 297 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 298 if (ACPI_FAILURE (Status)) 299 { 300 AcpiUtRemoveReference (BufferDesc); 301 } 302 else 303 { 304 *RetBufferDesc = BufferDesc; 305 } 306 return_ACPI_STATUS (Status); 307 } 308 309 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 310 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", 311 ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length)); 312 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 313 "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", 314 ObjDesc->CommonField.BitLength, 315 ObjDesc->CommonField.StartFieldBitOffset, 316 ObjDesc->CommonField.BaseByteOffset)); 317 318 /* Lock entire transaction if requested */ 319 320 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 321 322 /* Read from the field */ 323 324 Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length); 325 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 326 327 328 Exit: 329 if (ACPI_FAILURE (Status)) 330 { 331 AcpiUtRemoveReference (BufferDesc); 332 } 333 else 334 { 335 *RetBufferDesc = BufferDesc; 336 } 337 338 return_ACPI_STATUS (Status); 339 } 340 341 342 /******************************************************************************* 343 * 344 * FUNCTION: AcpiExWriteDataToField 345 * 346 * PARAMETERS: SourceDesc - Contains data to write 347 * ObjDesc - The named field 348 * ResultDesc - Where the return value is returned, if any 349 * 350 * RETURN: Status 351 * 352 * DESCRIPTION: Write to a named field 353 * 354 ******************************************************************************/ 355 356 ACPI_STATUS 357 AcpiExWriteDataToField ( 358 ACPI_OPERAND_OBJECT *SourceDesc, 359 ACPI_OPERAND_OBJECT *ObjDesc, 360 ACPI_OPERAND_OBJECT **ResultDesc) 361 { 362 ACPI_STATUS Status; 363 UINT32 Length; 364 void *Buffer; 365 ACPI_OPERAND_OBJECT *BufferDesc; 366 UINT32 Function; 367 UINT16 AccessorType; 368 369 370 ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc); 371 372 373 /* Parameter validation */ 374 375 if (!SourceDesc || !ObjDesc) 376 { 377 return_ACPI_STATUS (AE_AML_NO_OPERAND); 378 } 379 380 if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) 381 { 382 /* 383 * If the BufferField arguments have not been previously evaluated, 384 * evaluate them now and save the results. 385 */ 386 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 387 { 388 Status = AcpiDsGetBufferFieldArguments (ObjDesc); 389 if (ACPI_FAILURE (Status)) 390 { 391 return_ACPI_STATUS (Status); 392 } 393 } 394 } 395 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 396 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 397 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS || 398 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) 399 { 400 /* 401 * This is an SMBus, GSBus or IPMI write. We will bypass the entire field 402 * mechanism and handoff the buffer directly to the handler. For 403 * these address spaces, the buffer is bi-directional; on a write, 404 * return data is returned in the same buffer. 405 * 406 * Source must be a buffer of sufficient size: 407 * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. 408 * 409 * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function 410 */ 411 if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER) 412 { 413 ACPI_ERROR ((AE_INFO, 414 "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", 415 AcpiUtGetObjectTypeName (SourceDesc))); 416 417 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 418 } 419 420 if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 421 { 422 Length = ACPI_SMBUS_BUFFER_SIZE; 423 Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16); 424 } 425 else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) 426 { 427 AccessorType = ObjDesc->Field.Attribute; 428 Length = AcpiExGetSerialAccessLength (AccessorType, 429 ObjDesc->Field.AccessLength); 430 431 /* 432 * Add additional 2 bytes for the GenericSerialBus data buffer: 433 * 434 * Status; (Byte 0 of the data buffer) 435 * Length; (Byte 1 of the data buffer) 436 * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) 437 */ 438 Length += 2; 439 Function = ACPI_WRITE | (AccessorType << 16); 440 } 441 else /* IPMI */ 442 { 443 Length = ACPI_IPMI_BUFFER_SIZE; 444 Function = ACPI_WRITE; 445 } 446 447 if (SourceDesc->Buffer.Length < Length) 448 { 449 ACPI_ERROR ((AE_INFO, 450 "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", 451 Length, SourceDesc->Buffer.Length)); 452 453 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); 454 } 455 456 /* Create the bi-directional buffer */ 457 458 BufferDesc = AcpiUtCreateBufferObject (Length); 459 if (!BufferDesc) 460 { 461 return_ACPI_STATUS (AE_NO_MEMORY); 462 } 463 464 Buffer = BufferDesc->Buffer.Pointer; 465 ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length); 466 467 /* Lock entire transaction if requested */ 468 469 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 470 471 /* 472 * Perform the write (returns status and perhaps data in the 473 * same buffer) 474 */ 475 Status = AcpiExAccessRegion (ObjDesc, 0, 476 (UINT64 *) Buffer, Function); 477 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 478 479 *ResultDesc = BufferDesc; 480 return_ACPI_STATUS (Status); 481 } 482 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 483 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO)) 484 { 485 /* 486 * For GPIO (GeneralPurposeIo), we will bypass the entire field 487 * mechanism and handoff the bit address and bit width directly to 488 * the handler. The Address will be the bit offset 489 * from the previous Connection() operator, making it effectively a 490 * pin number index. The BitLength is the length of the field, which 491 * is thus the number of pins. 492 */ 493 if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER) 494 { 495 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 496 } 497 498 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 499 "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", 500 AcpiUtGetTypeName (SourceDesc->Common.Type), 501 SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value, 502 ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength)); 503 504 Buffer = &SourceDesc->Integer.Value; 505 506 /* Lock entire transaction if requested */ 507 508 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 509 510 /* Perform the write */ 511 512 Status = AcpiExAccessRegion (ObjDesc, 0, 513 (UINT64 *) Buffer, ACPI_WRITE); 514 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 515 return_ACPI_STATUS (Status); 516 } 517 518 /* Get a pointer to the data to be written */ 519 520 switch (SourceDesc->Common.Type) 521 { 522 case ACPI_TYPE_INTEGER: 523 524 Buffer = &SourceDesc->Integer.Value; 525 Length = sizeof (SourceDesc->Integer.Value); 526 break; 527 528 case ACPI_TYPE_BUFFER: 529 530 Buffer = SourceDesc->Buffer.Pointer; 531 Length = SourceDesc->Buffer.Length; 532 break; 533 534 case ACPI_TYPE_STRING: 535 536 Buffer = SourceDesc->String.Pointer; 537 Length = SourceDesc->String.Length; 538 break; 539 540 default: 541 542 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 543 } 544 545 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 546 "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", 547 SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type), 548 SourceDesc->Common.Type, Buffer, Length)); 549 550 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 551 "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", 552 ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type), 553 ObjDesc->Common.Type, 554 ObjDesc->CommonField.BitLength, 555 ObjDesc->CommonField.StartFieldBitOffset, 556 ObjDesc->CommonField.BaseByteOffset)); 557 558 /* Lock entire transaction if requested */ 559 560 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 561 562 /* Write to the field */ 563 564 Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length); 565 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 566 567 return_ACPI_STATUS (Status); 568 } 569