exfldio.c revision 151937
1/****************************************************************************** 2 * 3 * Module Name: exfldio - Aml Field I/O 4 * $Revision: 1.116 $ 5 * 6 *****************************************************************************/ 7 8/****************************************************************************** 9 * 10 * 1. Copyright Notice 11 * 12 * Some or all of this work - Copyright (c) 1999 - 2005, Intel Corp. 13 * All rights reserved. 14 * 15 * 2. License 16 * 17 * 2.1. This is your license from Intel Corp. under its intellectual property 18 * rights. You may have additional license terms from the party that provided 19 * you this software, covering your right to use that party's intellectual 20 * property rights. 21 * 22 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 23 * copy of the source code appearing in this file ("Covered Code") an 24 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 25 * base code distributed originally by Intel ("Original Intel Code") to copy, 26 * make derivatives, distribute, use and display any portion of the Covered 27 * Code in any form, with the right to sublicense such rights; and 28 * 29 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 30 * license (with the right to sublicense), under only those claims of Intel 31 * patents that are infringed by the Original Intel Code, to make, use, sell, 32 * offer to sell, and import the Covered Code and derivative works thereof 33 * solely to the minimum extent necessary to exercise the above copyright 34 * license, and in no event shall the patent license extend to any additions 35 * to or modifications of the Original Intel Code. No other license or right 36 * is granted directly or by implication, estoppel or otherwise; 37 * 38 * The above copyright and patent license is granted only if the following 39 * conditions are met: 40 * 41 * 3. Conditions 42 * 43 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 44 * Redistribution of source code of any substantial portion of the Covered 45 * Code or modification with rights to further distribute source must include 46 * the above Copyright Notice, the above License, this list of Conditions, 47 * and the following Disclaimer and Export Compliance provision. In addition, 48 * Licensee must cause all Covered Code to which Licensee contributes to 49 * contain a file documenting the changes Licensee made to create that Covered 50 * Code and the date of any change. Licensee must include in that file the 51 * documentation of any changes made by any predecessor Licensee. Licensee 52 * must include a prominent statement that the modification is derived, 53 * directly or indirectly, from Original Intel Code. 54 * 55 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 56 * Redistribution of source code of any substantial portion of the Covered 57 * Code or modification without rights to further distribute source must 58 * include the following Disclaimer and Export Compliance provision in the 59 * documentation and/or other materials provided with distribution. In 60 * addition, Licensee may not authorize further sublicense of source of any 61 * portion of the Covered Code, and must include terms to the effect that the 62 * license from Licensee to its licensee is limited to the intellectual 63 * property embodied in the software Licensee provides to its licensee, and 64 * not to intellectual property embodied in modifications its licensee may 65 * make. 66 * 67 * 3.3. Redistribution of Executable. Redistribution in executable form of any 68 * substantial portion of the Covered Code or modification must reproduce the 69 * above Copyright Notice, and the following Disclaimer and Export Compliance 70 * provision in the documentation and/or other materials provided with the 71 * distribution. 72 * 73 * 3.4. Intel retains all right, title, and interest in and to the Original 74 * Intel Code. 75 * 76 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 77 * Intel shall be used in advertising or otherwise to promote the sale, use or 78 * other dealings in products derived from or relating to the Covered Code 79 * without prior written authorization from Intel. 80 * 81 * 4. Disclaimer and Export Compliance 82 * 83 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 84 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 85 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 86 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 87 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 88 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 89 * PARTICULAR PURPOSE. 90 * 91 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 92 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 93 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 94 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 95 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 96 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 97 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 98 * LIMITED REMEDY. 99 * 100 * 4.3. Licensee shall not export, either directly or indirectly, any of this 101 * software or system incorporating such software without first obtaining any 102 * required license or other approval from the U. S. Department of Commerce or 103 * any other agency or department of the United States Government. In the 104 * event Licensee exports any such software from the United States or 105 * re-exports any such software from a foreign destination, Licensee shall 106 * ensure that the distribution and export/re-export of the software is in 107 * compliance with all laws, regulations, orders, or other restrictions of the 108 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 109 * any of its subsidiaries will export/re-export any technical data, process, 110 * software, or service, directly or indirectly, to any country for which the 111 * United States government or any agency thereof requires an export license, 112 * other governmental approval, or letter of assurance, without first obtaining 113 * such license, approval or letter. 114 * 115 *****************************************************************************/ 116 117 118#define __EXFLDIO_C__ 119 120#include <contrib/dev/acpica/acpi.h> 121#include <contrib/dev/acpica/acinterp.h> 122#include <contrib/dev/acpica/amlcode.h> 123#include <contrib/dev/acpica/acevents.h> 124#include <contrib/dev/acpica/acdispat.h> 125 126 127#define _COMPONENT ACPI_EXECUTER 128 ACPI_MODULE_NAME ("exfldio") 129 130/* Local prototypes */ 131 132static ACPI_STATUS 133AcpiExFieldDatumIo ( 134 ACPI_OPERAND_OBJECT *ObjDesc, 135 UINT32 FieldDatumByteOffset, 136 ACPI_INTEGER *Value, 137 UINT32 ReadWrite); 138 139static BOOLEAN 140AcpiExRegisterOverflow ( 141 ACPI_OPERAND_OBJECT *ObjDesc, 142 ACPI_INTEGER Value); 143 144static ACPI_STATUS 145AcpiExSetupRegion ( 146 ACPI_OPERAND_OBJECT *ObjDesc, 147 UINT32 FieldDatumByteOffset); 148 149 150/******************************************************************************* 151 * 152 * FUNCTION: AcpiExSetupRegion 153 * 154 * PARAMETERS: ObjDesc - Field to be read or written 155 * FieldDatumByteOffset - Byte offset of this datum within the 156 * parent field 157 * 158 * RETURN: Status 159 * 160 * DESCRIPTION: Common processing for AcpiExExtractFromField and 161 * AcpiExInsertIntoField. Initialize the Region if necessary and 162 * validate the request. 163 * 164 ******************************************************************************/ 165 166static ACPI_STATUS 167AcpiExSetupRegion ( 168 ACPI_OPERAND_OBJECT *ObjDesc, 169 UINT32 FieldDatumByteOffset) 170{ 171 ACPI_STATUS Status = AE_OK; 172 ACPI_OPERAND_OBJECT *RgnDesc; 173 174 175 ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset); 176 177 178 RgnDesc = ObjDesc->CommonField.RegionObj; 179 180 /* We must have a valid region */ 181 182 if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION) 183 { 184 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n", 185 ACPI_GET_OBJECT_TYPE (RgnDesc), 186 AcpiUtGetObjectTypeName (RgnDesc))); 187 188 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 189 } 190 191 /* 192 * If the Region Address and Length have not been previously evaluated, 193 * evaluate them now and save the results. 194 */ 195 if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) 196 { 197 Status = AcpiDsGetRegionArguments (RgnDesc); 198 if (ACPI_FAILURE (Status)) 199 { 200 return_ACPI_STATUS (Status); 201 } 202 } 203 204 if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 205 { 206 /* SMBus has a non-linear address space */ 207 208 return_ACPI_STATUS (AE_OK); 209 } 210 211#ifdef ACPI_UNDER_DEVELOPMENT 212 /* 213 * If the Field access is AnyAcc, we can now compute the optimal 214 * access (because we know know the length of the parent region) 215 */ 216 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 217 { 218 if (ACPI_FAILURE (Status)) 219 { 220 return_ACPI_STATUS (Status); 221 } 222 } 223#endif 224 225 /* 226 * Validate the request. The entire request from the byte offset for a 227 * length of one field datum (access width) must fit within the region. 228 * (Region length is specified in bytes) 229 */ 230 if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset + 231 FieldDatumByteOffset + 232 ObjDesc->CommonField.AccessByteWidth)) 233 { 234 if (AcpiGbl_EnableInterpreterSlack) 235 { 236 /* 237 * Slack mode only: We will go ahead and allow access to this 238 * field if it is within the region length rounded up to the next 239 * access width boundary. 240 */ 241 if (ACPI_ROUND_UP (RgnDesc->Region.Length, 242 ObjDesc->CommonField.AccessByteWidth) >= 243 (ObjDesc->CommonField.BaseByteOffset + 244 (ACPI_NATIVE_UINT) ObjDesc->CommonField.AccessByteWidth + 245 FieldDatumByteOffset)) 246 { 247 return_ACPI_STATUS (AE_OK); 248 } 249 } 250 251 if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth) 252 { 253 /* 254 * This is the case where the AccessType (AccWord, etc.) is wider 255 * than the region itself. For example, a region of length one 256 * byte, and a field with Dword access specified. 257 */ 258 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 259 "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", 260 AcpiUtGetNodeName (ObjDesc->CommonField.Node), 261 ObjDesc->CommonField.AccessByteWidth, 262 AcpiUtGetNodeName (RgnDesc->Region.Node), 263 RgnDesc->Region.Length)); 264 } 265 266 /* 267 * Offset rounded up to next multiple of field width 268 * exceeds region length, indicate an error 269 */ 270 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 271 "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", 272 AcpiUtGetNodeName (ObjDesc->CommonField.Node), 273 ObjDesc->CommonField.BaseByteOffset, 274 FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, 275 AcpiUtGetNodeName (RgnDesc->Region.Node), 276 RgnDesc->Region.Length)); 277 278 return_ACPI_STATUS (AE_AML_REGION_LIMIT); 279 } 280 281 return_ACPI_STATUS (AE_OK); 282} 283 284 285/******************************************************************************* 286 * 287 * FUNCTION: AcpiExAccessRegion 288 * 289 * PARAMETERS: ObjDesc - Field to be read 290 * FieldDatumByteOffset - Byte offset of this datum within the 291 * parent field 292 * Value - Where to store value (must at least 293 * the size of ACPI_INTEGER) 294 * Function - Read or Write flag plus other region- 295 * dependent flags 296 * 297 * RETURN: Status 298 * 299 * DESCRIPTION: Read or Write a single field datum to an Operation Region. 300 * 301 ******************************************************************************/ 302 303ACPI_STATUS 304AcpiExAccessRegion ( 305 ACPI_OPERAND_OBJECT *ObjDesc, 306 UINT32 FieldDatumByteOffset, 307 ACPI_INTEGER *Value, 308 UINT32 Function) 309{ 310 ACPI_STATUS Status; 311 ACPI_OPERAND_OBJECT *RgnDesc; 312 ACPI_PHYSICAL_ADDRESS Address; 313 314 315 ACPI_FUNCTION_TRACE ("ExAccessRegion"); 316 317 318 /* 319 * Ensure that the region operands are fully evaluated and verify 320 * the validity of the request 321 */ 322 Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset); 323 if (ACPI_FAILURE (Status)) 324 { 325 return_ACPI_STATUS (Status); 326 } 327 328 /* 329 * The physical address of this field datum is: 330 * 331 * 1) The base of the region, plus 332 * 2) The base offset of the field, plus 333 * 3) The current offset into the field 334 */ 335 RgnDesc = ObjDesc->CommonField.RegionObj; 336 Address = RgnDesc->Region.Address + 337 ObjDesc->CommonField.BaseByteOffset + 338 FieldDatumByteOffset; 339 340 if ((Function & ACPI_IO_MASK) == ACPI_READ) 341 { 342 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); 343 } 344 else 345 { 346 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); 347 } 348 349 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, 350 " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", 351 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 352 RgnDesc->Region.SpaceId, 353 ObjDesc->CommonField.AccessByteWidth, 354 ObjDesc->CommonField.BaseByteOffset, 355 FieldDatumByteOffset, 356 ACPI_FORMAT_UINT64 (Address))); 357 358 /* Invoke the appropriate AddressSpace/OpRegion handler */ 359 360 Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, 361 Address, 362 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); 363 364 if (ACPI_FAILURE (Status)) 365 { 366 if (Status == AE_NOT_IMPLEMENTED) 367 { 368 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 369 "Region %s(%X) not implemented\n", 370 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 371 RgnDesc->Region.SpaceId)); 372 } 373 else if (Status == AE_NOT_EXIST) 374 { 375 ACPI_REPORT_ERROR (( 376 "Region %s(%X) has no handler\n", 377 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 378 RgnDesc->Region.SpaceId)); 379 } 380 } 381 382 return_ACPI_STATUS (Status); 383} 384 385 386/******************************************************************************* 387 * 388 * FUNCTION: AcpiExRegisterOverflow 389 * 390 * PARAMETERS: ObjDesc - Register(Field) to be written 391 * Value - Value to be stored 392 * 393 * RETURN: TRUE if value overflows the field, FALSE otherwise 394 * 395 * DESCRIPTION: Check if a value is out of range of the field being written. 396 * Used to check if the values written to Index and Bank registers 397 * are out of range. Normally, the value is simply truncated 398 * to fit the field, but this case is most likely a serious 399 * coding error in the ASL. 400 * 401 ******************************************************************************/ 402 403static BOOLEAN 404AcpiExRegisterOverflow ( 405 ACPI_OPERAND_OBJECT *ObjDesc, 406 ACPI_INTEGER Value) 407{ 408 409 if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE) 410 { 411 /* 412 * The field is large enough to hold the maximum integer, so we can 413 * never overflow it. 414 */ 415 return (FALSE); 416 } 417 418 if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength)) 419 { 420 /* 421 * The Value is larger than the maximum value that can fit into 422 * the register. 423 */ 424 return (TRUE); 425 } 426 427 /* The Value will fit into the field with no truncation */ 428 429 return (FALSE); 430} 431 432 433/******************************************************************************* 434 * 435 * FUNCTION: AcpiExFieldDatumIo 436 * 437 * PARAMETERS: ObjDesc - Field to be read 438 * FieldDatumByteOffset - Byte offset of this datum within the 439 * parent field 440 * Value - Where to store value (must be 64 bits) 441 * ReadWrite - Read or Write flag 442 * 443 * RETURN: Status 444 * 445 * DESCRIPTION: Read or Write a single datum of a field. The FieldType is 446 * demultiplexed here to handle the different types of fields 447 * (BufferField, RegionField, IndexField, BankField) 448 * 449 ******************************************************************************/ 450 451static ACPI_STATUS 452AcpiExFieldDatumIo ( 453 ACPI_OPERAND_OBJECT *ObjDesc, 454 UINT32 FieldDatumByteOffset, 455 ACPI_INTEGER *Value, 456 UINT32 ReadWrite) 457{ 458 ACPI_STATUS Status; 459 ACPI_INTEGER LocalValue; 460 461 462 ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset); 463 464 465 if (ReadWrite == ACPI_READ) 466 { 467 if (!Value) 468 { 469 LocalValue = 0; 470 471 /* To support reads without saving return value */ 472 Value = &LocalValue; 473 } 474 475 /* Clear the entire return buffer first, [Very Important!] */ 476 477 *Value = 0; 478 } 479 480 /* 481 * The four types of fields are: 482 * 483 * BufferField - Read/write from/to a Buffer 484 * RegionField - Read/write from/to a Operation Region. 485 * BankField - Write to a Bank Register, then read/write from/to an 486 * OperationRegion 487 * IndexField - Write to an Index Register, then read/write from/to a 488 * Data Register 489 */ 490 switch (ACPI_GET_OBJECT_TYPE (ObjDesc)) 491 { 492 case ACPI_TYPE_BUFFER_FIELD: 493 /* 494 * If the BufferField arguments have not been previously evaluated, 495 * evaluate them now and save the results. 496 */ 497 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 498 { 499 Status = AcpiDsGetBufferFieldArguments (ObjDesc); 500 if (ACPI_FAILURE (Status)) 501 { 502 return_ACPI_STATUS (Status); 503 } 504 } 505 506 if (ReadWrite == ACPI_READ) 507 { 508 /* 509 * Copy the data from the source buffer. 510 * Length is the field width in bytes. 511 */ 512 ACPI_MEMCPY (Value, 513 (ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 514 ObjDesc->BufferField.BaseByteOffset + 515 FieldDatumByteOffset, 516 ObjDesc->CommonField.AccessByteWidth); 517 } 518 else 519 { 520 /* 521 * Copy the data to the target buffer. 522 * Length is the field width in bytes. 523 */ 524 ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 525 ObjDesc->BufferField.BaseByteOffset + 526 FieldDatumByteOffset, 527 Value, ObjDesc->CommonField.AccessByteWidth); 528 } 529 530 Status = AE_OK; 531 break; 532 533 534 case ACPI_TYPE_LOCAL_BANK_FIELD: 535 536 /* 537 * Ensure that the BankValue is not beyond the capacity of 538 * the register 539 */ 540 if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, 541 (ACPI_INTEGER) ObjDesc->BankField.Value)) 542 { 543 return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 544 } 545 546 /* 547 * For BankFields, we must write the BankValue to the BankRegister 548 * (itself a RegionField) before we can access the data. 549 */ 550 Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, 551 &ObjDesc->BankField.Value, 552 sizeof (ObjDesc->BankField.Value)); 553 if (ACPI_FAILURE (Status)) 554 { 555 return_ACPI_STATUS (Status); 556 } 557 558 /* 559 * Now that the Bank has been selected, fall through to the 560 * RegionField case and write the datum to the Operation Region 561 */ 562 563 /*lint -fallthrough */ 564 565 566 case ACPI_TYPE_LOCAL_REGION_FIELD: 567 /* 568 * For simple RegionFields, we just directly access the owning 569 * Operation Region. 570 */ 571 Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value, 572 ReadWrite); 573 break; 574 575 576 case ACPI_TYPE_LOCAL_INDEX_FIELD: 577 578 579 /* 580 * Ensure that the IndexValue is not beyond the capacity of 581 * the register 582 */ 583 if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, 584 (ACPI_INTEGER) ObjDesc->IndexField.Value)) 585 { 586 return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 587 } 588 589 /* Write the index value to the IndexRegister (itself a RegionField) */ 590 591 FieldDatumByteOffset += ObjDesc->IndexField.Value; 592 593 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 594 "Write to Index Register: Value %8.8X\n", 595 FieldDatumByteOffset)); 596 597 Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, 598 &FieldDatumByteOffset, 599 sizeof (FieldDatumByteOffset)); 600 if (ACPI_FAILURE (Status)) 601 { 602 return_ACPI_STATUS (Status); 603 } 604 605 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 606 "I/O to Data Register: ValuePtr %p\n", 607 Value)); 608 609 if (ReadWrite == ACPI_READ) 610 { 611 /* Read the datum from the DataRegister */ 612 613 Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj, 614 Value, sizeof (ACPI_INTEGER)); 615 } 616 else 617 { 618 /* Write the datum to the DataRegister */ 619 620 Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj, 621 Value, sizeof (ACPI_INTEGER)); 622 } 623 break; 624 625 626 default: 627 628 ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n", 629 ACPI_GET_OBJECT_TYPE (ObjDesc))); 630 Status = AE_AML_INTERNAL; 631 break; 632 } 633 634 if (ACPI_SUCCESS (Status)) 635 { 636 if (ReadWrite == ACPI_READ) 637 { 638 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 639 "Value Read %8.8X%8.8X, Width %d\n", 640 ACPI_FORMAT_UINT64 (*Value), 641 ObjDesc->CommonField.AccessByteWidth)); 642 } 643 else 644 { 645 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 646 "Value Written %8.8X%8.8X, Width %d\n", 647 ACPI_FORMAT_UINT64 (*Value), 648 ObjDesc->CommonField.AccessByteWidth)); 649 } 650 } 651 652 return_ACPI_STATUS (Status); 653} 654 655 656/******************************************************************************* 657 * 658 * FUNCTION: AcpiExWriteWithUpdateRule 659 * 660 * PARAMETERS: ObjDesc - Field to be written 661 * Mask - bitmask within field datum 662 * FieldValue - Value to write 663 * FieldDatumByteOffset - Offset of datum within field 664 * 665 * RETURN: Status 666 * 667 * DESCRIPTION: Apply the field update rule to a field write 668 * 669 ******************************************************************************/ 670 671ACPI_STATUS 672AcpiExWriteWithUpdateRule ( 673 ACPI_OPERAND_OBJECT *ObjDesc, 674 ACPI_INTEGER Mask, 675 ACPI_INTEGER FieldValue, 676 UINT32 FieldDatumByteOffset) 677{ 678 ACPI_STATUS Status = AE_OK; 679 ACPI_INTEGER MergedValue; 680 ACPI_INTEGER CurrentValue; 681 682 683 ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask); 684 685 686 /* Start with the new bits */ 687 688 MergedValue = FieldValue; 689 690 /* If the mask is all ones, we don't need to worry about the update rule */ 691 692 if (Mask != ACPI_INTEGER_MAX) 693 { 694 /* Decode the update rule */ 695 696 switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) 697 { 698 case AML_FIELD_UPDATE_PRESERVE: 699 /* 700 * Check if update rule needs to be applied (not if mask is all 701 * ones) The left shift drops the bits we want to ignore. 702 */ 703 if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - 704 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) 705 { 706 /* 707 * Read the current contents of the byte/word/dword containing 708 * the field, and merge with the new field value. 709 */ 710 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 711 &CurrentValue, ACPI_READ); 712 if (ACPI_FAILURE (Status)) 713 { 714 return_ACPI_STATUS (Status); 715 } 716 717 MergedValue |= (CurrentValue & ~Mask); 718 } 719 break; 720 721 case AML_FIELD_UPDATE_WRITE_AS_ONES: 722 723 /* Set positions outside the field to all ones */ 724 725 MergedValue |= ~Mask; 726 break; 727 728 case AML_FIELD_UPDATE_WRITE_AS_ZEROS: 729 730 /* Set positions outside the field to all zeros */ 731 732 MergedValue &= Mask; 733 break; 734 735 default: 736 737 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 738 "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n", 739 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); 740 return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 741 } 742 } 743 744 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 745 "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", 746 ACPI_FORMAT_UINT64 (Mask), 747 FieldDatumByteOffset, 748 ObjDesc->CommonField.AccessByteWidth, 749 ACPI_FORMAT_UINT64 (FieldValue), 750 ACPI_FORMAT_UINT64 (MergedValue))); 751 752 /* Write the merged value */ 753 754 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 755 &MergedValue, ACPI_WRITE); 756 757 return_ACPI_STATUS (Status); 758} 759 760 761/******************************************************************************* 762 * 763 * FUNCTION: AcpiExExtractFromField 764 * 765 * PARAMETERS: ObjDesc - Field to be read 766 * Buffer - Where to store the field data 767 * BufferLength - Length of Buffer 768 * 769 * RETURN: Status 770 * 771 * DESCRIPTION: Retrieve the current value of the given field 772 * 773 ******************************************************************************/ 774 775ACPI_STATUS 776AcpiExExtractFromField ( 777 ACPI_OPERAND_OBJECT *ObjDesc, 778 void *Buffer, 779 UINT32 BufferLength) 780{ 781 ACPI_STATUS Status; 782 ACPI_INTEGER RawDatum; 783 ACPI_INTEGER MergedDatum; 784 UINT32 FieldOffset = 0; 785 UINT32 BufferOffset = 0; 786 UINT32 BufferTailBits; 787 UINT32 DatumCount; 788 UINT32 FieldDatumCount; 789 UINT32 i; 790 791 792 ACPI_FUNCTION_TRACE ("ExExtractFromField"); 793 794 795 /* Validate target buffer and clear it */ 796 797 if (BufferLength < ACPI_ROUND_BITS_UP_TO_BYTES ( 798 ObjDesc->CommonField.BitLength)) 799 { 800 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 801 "Field size %X (bits) is too large for buffer (%X)\n", 802 ObjDesc->CommonField.BitLength, BufferLength)); 803 804 return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 805 } 806 ACPI_MEMSET (Buffer, 0, BufferLength); 807 808 /* Compute the number of datums (access width data items) */ 809 810 DatumCount = ACPI_ROUND_UP_TO ( 811 ObjDesc->CommonField.BitLength, 812 ObjDesc->CommonField.AccessBitWidth); 813 FieldDatumCount = ACPI_ROUND_UP_TO ( 814 ObjDesc->CommonField.BitLength + 815 ObjDesc->CommonField.StartFieldBitOffset, 816 ObjDesc->CommonField.AccessBitWidth); 817 818 /* Priming read from the field */ 819 820 Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); 821 if (ACPI_FAILURE (Status)) 822 { 823 return_ACPI_STATUS (Status); 824 } 825 MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 826 827 /* Read the rest of the field */ 828 829 for (i = 1; i < FieldDatumCount; i++) 830 { 831 /* Get next input datum from the field */ 832 833 FieldOffset += ObjDesc->CommonField.AccessByteWidth; 834 Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, 835 &RawDatum, ACPI_READ); 836 if (ACPI_FAILURE (Status)) 837 { 838 return_ACPI_STATUS (Status); 839 } 840 841 /* Merge with previous datum if necessary */ 842 843 MergedDatum |= RawDatum << 844 (ObjDesc->CommonField.AccessBitWidth - 845 ObjDesc->CommonField.StartFieldBitOffset); 846 847 if (i == DatumCount) 848 { 849 break; 850 } 851 852 /* Write merged datum to target buffer */ 853 854 ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 855 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 856 BufferLength - BufferOffset)); 857 858 BufferOffset += ObjDesc->CommonField.AccessByteWidth; 859 MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 860 } 861 862 /* Mask off any extra bits in the last datum */ 863 864 BufferTailBits = ObjDesc->CommonField.BitLength % 865 ObjDesc->CommonField.AccessBitWidth; 866 if (BufferTailBits) 867 { 868 MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 869 } 870 871 /* Write the last datum to the buffer */ 872 873 ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 874 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 875 BufferLength - BufferOffset)); 876 877 return_ACPI_STATUS (AE_OK); 878} 879 880 881/******************************************************************************* 882 * 883 * FUNCTION: AcpiExInsertIntoField 884 * 885 * PARAMETERS: ObjDesc - Field to be written 886 * Buffer - Data to be written 887 * BufferLength - Length of Buffer 888 * 889 * RETURN: Status 890 * 891 * DESCRIPTION: Store the Buffer contents into the given field 892 * 893 ******************************************************************************/ 894 895ACPI_STATUS 896AcpiExInsertIntoField ( 897 ACPI_OPERAND_OBJECT *ObjDesc, 898 void *Buffer, 899 UINT32 BufferLength) 900{ 901 ACPI_STATUS Status; 902 ACPI_INTEGER Mask; 903 ACPI_INTEGER MergedDatum; 904 ACPI_INTEGER RawDatum = 0; 905 UINT32 FieldOffset = 0; 906 UINT32 BufferOffset = 0; 907 UINT32 BufferTailBits; 908 UINT32 DatumCount; 909 UINT32 FieldDatumCount; 910 UINT32 i; 911 912 913 ACPI_FUNCTION_TRACE ("ExInsertIntoField"); 914 915 916 /* Validate input buffer */ 917 918 if (BufferLength < ACPI_ROUND_BITS_UP_TO_BYTES ( 919 ObjDesc->CommonField.BitLength)) 920 { 921 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 922 "Field size %X (bits) is too large for buffer (%X)\n", 923 ObjDesc->CommonField.BitLength, BufferLength)); 924 925 return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 926 } 927 928 /* Compute the number of datums (access width data items) */ 929 930 Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); 931 DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, 932 ObjDesc->CommonField.AccessBitWidth); 933 FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + 934 ObjDesc->CommonField.StartFieldBitOffset, 935 ObjDesc->CommonField.AccessBitWidth); 936 937 /* Get initial Datum from the input buffer */ 938 939 ACPI_MEMCPY (&RawDatum, Buffer, 940 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 941 BufferLength - BufferOffset)); 942 943 MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 944 945 /* Write the entire field */ 946 947 for (i = 1; i < FieldDatumCount; i++) 948 { 949 /* Write merged datum to the target field */ 950 951 MergedDatum &= Mask; 952 Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, 953 MergedDatum, FieldOffset); 954 if (ACPI_FAILURE (Status)) 955 { 956 return_ACPI_STATUS (Status); 957 } 958 959 /* Start new output datum by merging with previous input datum */ 960 961 FieldOffset += ObjDesc->CommonField.AccessByteWidth; 962 MergedDatum = RawDatum >> 963 (ObjDesc->CommonField.AccessBitWidth - 964 ObjDesc->CommonField.StartFieldBitOffset); 965 Mask = ACPI_INTEGER_MAX; 966 967 if (i == DatumCount) 968 { 969 break; 970 } 971 972 /* Get the next input datum from the buffer */ 973 974 BufferOffset += ObjDesc->CommonField.AccessByteWidth; 975 ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset, 976 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 977 BufferLength - BufferOffset)); 978 MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 979 } 980 981 /* Mask off any extra bits in the last datum */ 982 983 BufferTailBits = (ObjDesc->CommonField.BitLength + 984 ObjDesc->CommonField.StartFieldBitOffset) % 985 ObjDesc->CommonField.AccessBitWidth; 986 if (BufferTailBits) 987 { 988 Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 989 } 990 991 /* Write the last datum to the field */ 992 993 MergedDatum &= Mask; 994 Status = AcpiExWriteWithUpdateRule (ObjDesc, 995 Mask, MergedDatum, FieldOffset); 996 997 return_ACPI_STATUS (Status); 998} 999 1000 1001