1 /******************************************************************************* 2 * 3 * Module Name: hwregs - Read/write access functions for the various ACPI 4 * control and status registers. 5 * 6 ******************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2016, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 #include "acpi.h" 46 #include "accommon.h" 47 #include "acevents.h" 48 49 #define _COMPONENT ACPI_HARDWARE 50 ACPI_MODULE_NAME ("hwregs") 51 52 53 #if (!ACPI_REDUCED_HARDWARE) 54 55 /* Local Prototypes */ 56 57 static ACPI_STATUS 58 AcpiHwReadMultiple ( 59 UINT32 *Value, 60 ACPI_GENERIC_ADDRESS *RegisterA, 61 ACPI_GENERIC_ADDRESS *RegisterB); 62 63 static ACPI_STATUS 64 AcpiHwWriteMultiple ( 65 UINT32 Value, 66 ACPI_GENERIC_ADDRESS *RegisterA, 67 ACPI_GENERIC_ADDRESS *RegisterB); 68 69 #endif /* !ACPI_REDUCED_HARDWARE */ 70 71 72 /****************************************************************************** 73 * 74 * FUNCTION: AcpiHwValidateRegister 75 * 76 * PARAMETERS: Reg - GAS register structure 77 * MaxBitWidth - Max BitWidth supported (32 or 64) 78 * Address - Pointer to where the gas->address 79 * is returned 80 * 81 * RETURN: Status 82 * 83 * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS 84 * pointer, Address, SpaceId, BitWidth, and BitOffset. 85 * 86 ******************************************************************************/ 87 88 ACPI_STATUS 89 AcpiHwValidateRegister ( 90 ACPI_GENERIC_ADDRESS *Reg, 91 UINT8 MaxBitWidth, 92 UINT64 *Address) 93 { 94 UINT8 BitWidth; 95 UINT8 AccessWidth; 96 97 98 /* Must have a valid pointer to a GAS structure */ 99 100 if (!Reg) 101 { 102 return (AE_BAD_PARAMETER); 103 } 104 105 /* 106 * Copy the target address. This handles possible alignment issues. 107 * Address must not be null. A null address also indicates an optional 108 * ACPI register that is not supported, so no error message. 109 */ 110 ACPI_MOVE_64_TO_64 (Address, &Reg->Address); 111 if (!(*Address)) 112 { 113 return (AE_BAD_ADDRESS); 114 } 115 116 /* Validate the SpaceID */ 117 118 if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 119 (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) 120 { 121 ACPI_ERROR ((AE_INFO, 122 "Unsupported address space: 0x%X", Reg->SpaceId)); 123 return (AE_SUPPORT); 124 } 125 126 /* Validate the AccessWidth */ 127 128 if (Reg->AccessWidth > 4) 129 { 130 ACPI_ERROR ((AE_INFO, 131 "Unsupported register access width: 0x%X", Reg->AccessWidth)); 132 return (AE_SUPPORT); 133 } 134 135 /* Validate the BitWidth, convert AccessWidth into number of bits */ 136 137 AccessWidth = Reg->AccessWidth ? Reg->AccessWidth : 1; 138 AccessWidth = 1 << (AccessWidth + 2); 139 BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth); 140 if (MaxBitWidth < BitWidth) 141 { 142 ACPI_WARNING ((AE_INFO, 143 "Requested bit width 0x%X is smaller than register bit width 0x%X", 144 MaxBitWidth, BitWidth)); 145 return (AE_SUPPORT); 146 } 147 148 return (AE_OK); 149 } 150 151 152 /****************************************************************************** 153 * 154 * FUNCTION: AcpiHwRead 155 * 156 * PARAMETERS: Value - Where the value is returned 157 * Reg - GAS register structure 158 * 159 * RETURN: Status 160 * 161 * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max 162 * version of AcpiRead, used internally since the overhead of 163 * 64-bit values is not needed. 164 * 165 * LIMITATIONS: <These limitations also apply to AcpiHwWrite> 166 * SpaceID must be SystemMemory or SystemIO. 167 * 168 ******************************************************************************/ 169 170 ACPI_STATUS 171 AcpiHwRead ( 172 UINT32 *Value, 173 ACPI_GENERIC_ADDRESS *Reg) 174 { 175 UINT64 Address; 176 UINT8 AccessWidth; 177 UINT32 BitWidth; 178 UINT8 BitOffset; 179 UINT64 Value64; 180 UINT32 Value32; 181 UINT8 Index; 182 ACPI_STATUS Status; 183 184 185 ACPI_FUNCTION_NAME (HwRead); 186 187 188 /* Validate contents of the GAS register */ 189 190 Status = AcpiHwValidateRegister (Reg, 32, &Address); 191 if (ACPI_FAILURE (Status)) 192 { 193 return (Status); 194 } 195 196 /* 197 * Initialize entire 32-bit return value to zero, convert AccessWidth 198 * into number of bits based 199 */ 200 *Value = 0; 201 AccessWidth = Reg->AccessWidth ? Reg->AccessWidth : 1; 202 AccessWidth = 1 << (AccessWidth + 2); 203 BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth); 204 BitOffset = Reg->BitOffset; 205 206 /* 207 * Two address spaces supported: Memory or IO. PCI_Config is 208 * not supported here because the GAS structure is insufficient 209 */ 210 Index = 0; 211 while (BitWidth) 212 { 213 if (BitOffset > AccessWidth) 214 { 215 Value32 = 0; 216 BitOffset -= AccessWidth; 217 } 218 else 219 { 220 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 221 { 222 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) 223 Address + Index * ACPI_DIV_8 (AccessWidth), 224 &Value64, AccessWidth); 225 Value32 = (UINT32) Value64; 226 } 227 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 228 { 229 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) 230 Address + Index * ACPI_DIV_8 (AccessWidth), 231 &Value32, AccessWidth); 232 } 233 234 if (BitOffset) 235 { 236 Value32 &= ACPI_MASK_BITS_BELOW (BitOffset); 237 BitOffset = 0; 238 } 239 if (BitWidth < AccessWidth) 240 { 241 Value32 &= ACPI_MASK_BITS_ABOVE (BitWidth); 242 } 243 } 244 245 ACPI_SET_BITS (Value, Index * AccessWidth, 246 ((1UL << AccessWidth) - 1), Value32); 247 248 BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth; 249 Index++; 250 } 251 252 ACPI_DEBUG_PRINT ((ACPI_DB_IO, 253 "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", 254 *Value, AccessWidth, ACPI_FORMAT_UINT64 (Address), 255 AcpiUtGetRegionName (Reg->SpaceId))); 256 257 return (Status); 258 } 259 260 261 /****************************************************************************** 262 * 263 * FUNCTION: AcpiHwWrite 264 * 265 * PARAMETERS: Value - Value to be written 266 * Reg - GAS register structure 267 * 268 * RETURN: Status 269 * 270 * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max 271 * version of AcpiWrite, used internally since the overhead of 272 * 64-bit values is not needed. 273 * 274 ******************************************************************************/ 275 276 ACPI_STATUS 277 AcpiHwWrite ( 278 UINT32 Value, 279 ACPI_GENERIC_ADDRESS *Reg) 280 { 281 UINT64 Address; 282 UINT8 AccessWidth; 283 UINT32 BitWidth; 284 UINT8 BitOffset; 285 UINT64 Value64; 286 UINT32 NewValue32, OldValue32; 287 UINT8 Index; 288 ACPI_STATUS Status; 289 290 291 ACPI_FUNCTION_NAME (HwWrite); 292 293 294 /* Validate contents of the GAS register */ 295 296 Status = AcpiHwValidateRegister (Reg, 32, &Address); 297 if (ACPI_FAILURE (Status)) 298 { 299 return (Status); 300 } 301 302 /* Convert AccessWidth into number of bits based */ 303 304 AccessWidth = Reg->AccessWidth ? Reg->AccessWidth : 1; 305 AccessWidth = 1 << (AccessWidth + 2); 306 BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth); 307 BitOffset = Reg->BitOffset; 308 309 /* 310 * Two address spaces supported: Memory or IO. PCI_Config is 311 * not supported here because the GAS structure is insufficient 312 */ 313 Index = 0; 314 while (BitWidth) 315 { 316 NewValue32 = ACPI_GET_BITS (&Value, (Index * AccessWidth), 317 ((1 << AccessWidth) - 1)); 318 319 if (BitOffset > AccessWidth) 320 { 321 BitOffset -= AccessWidth; 322 } 323 else 324 { 325 if (BitOffset) 326 { 327 NewValue32 &= ACPI_MASK_BITS_BELOW (BitOffset); 328 } 329 330 if (BitWidth < AccessWidth) 331 { 332 NewValue32 &= ACPI_MASK_BITS_ABOVE (BitWidth); 333 } 334 335 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 336 { 337 if (BitOffset || BitWidth < AccessWidth) 338 { 339 /* 340 * Read old values in order not to modify the bits that 341 * are beyond the register BitWidth/BitOffset setting. 342 */ 343 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) 344 Address + Index * ACPI_DIV_8 (AccessWidth), 345 &Value64, AccessWidth); 346 OldValue32 = (UINT32) Value64; 347 348 if (BitOffset) 349 { 350 OldValue32 &= ACPI_MASK_BITS_ABOVE (BitOffset + 1); 351 BitOffset = 0; 352 } 353 354 if (BitWidth < AccessWidth) 355 { 356 OldValue32 &= ACPI_MASK_BITS_BELOW (BitWidth - 1); 357 } 358 359 NewValue32 |= OldValue32; 360 } 361 362 Value64 = (UINT64) NewValue32; 363 Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) 364 Address + Index * ACPI_DIV_8 (AccessWidth), 365 Value64, AccessWidth); 366 } 367 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 368 { 369 if (BitOffset || BitWidth < AccessWidth) 370 { 371 /* 372 * Read old values in order not to modify the bits that 373 * are beyond the register BitWidth/BitOffset setting. 374 */ 375 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) 376 Address + Index * ACPI_DIV_8 (AccessWidth), 377 &OldValue32, AccessWidth); 378 379 if (BitOffset) 380 { 381 OldValue32 &= ACPI_MASK_BITS_ABOVE (BitOffset + 1); 382 BitOffset = 0; 383 } 384 385 if (BitWidth < AccessWidth) 386 { 387 OldValue32 &= ACPI_MASK_BITS_BELOW (BitWidth - 1); 388 } 389 390 NewValue32 |= OldValue32; 391 } 392 393 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) 394 Address + Index * ACPI_DIV_8 (AccessWidth), 395 NewValue32, AccessWidth); 396 } 397 } 398 399 BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth; 400 Index++; 401 } 402 403 ACPI_DEBUG_PRINT ((ACPI_DB_IO, 404 "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", 405 Value, AccessWidth, ACPI_FORMAT_UINT64 (Address), 406 AcpiUtGetRegionName (Reg->SpaceId))); 407 408 return (Status); 409 } 410 411 412 #if (!ACPI_REDUCED_HARDWARE) 413 /******************************************************************************* 414 * 415 * FUNCTION: AcpiHwClearAcpiStatus 416 * 417 * PARAMETERS: None 418 * 419 * RETURN: Status 420 * 421 * DESCRIPTION: Clears all fixed and general purpose status bits 422 * 423 ******************************************************************************/ 424 425 ACPI_STATUS 426 AcpiHwClearAcpiStatus ( 427 void) 428 { 429 ACPI_STATUS Status; 430 ACPI_CPU_FLAGS LockFlags = 0; 431 432 433 ACPI_FUNCTION_TRACE (HwClearAcpiStatus); 434 435 436 ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", 437 ACPI_BITMASK_ALL_FIXED_STATUS, 438 ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); 439 440 LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); 441 442 /* Clear the fixed events in PM1 A/B */ 443 444 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, 445 ACPI_BITMASK_ALL_FIXED_STATUS); 446 447 AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); 448 449 if (ACPI_FAILURE (Status)) 450 { 451 goto Exit; 452 } 453 454 /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 455 456 Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); 457 458 Exit: 459 return_ACPI_STATUS (Status); 460 } 461 462 463 /******************************************************************************* 464 * 465 * FUNCTION: AcpiHwGetBitRegisterInfo 466 * 467 * PARAMETERS: RegisterId - Index of ACPI Register to access 468 * 469 * RETURN: The bitmask to be used when accessing the register 470 * 471 * DESCRIPTION: Map RegisterId into a register bitmask. 472 * 473 ******************************************************************************/ 474 475 ACPI_BIT_REGISTER_INFO * 476 AcpiHwGetBitRegisterInfo ( 477 UINT32 RegisterId) 478 { 479 ACPI_FUNCTION_ENTRY (); 480 481 482 if (RegisterId > ACPI_BITREG_MAX) 483 { 484 ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId)); 485 return (NULL); 486 } 487 488 return (&AcpiGbl_BitRegisterInfo[RegisterId]); 489 } 490 491 492 /****************************************************************************** 493 * 494 * FUNCTION: AcpiHwWritePm1Control 495 * 496 * PARAMETERS: Pm1aControl - Value to be written to PM1A control 497 * Pm1bControl - Value to be written to PM1B control 498 * 499 * RETURN: Status 500 * 501 * DESCRIPTION: Write the PM1 A/B control registers. These registers are 502 * different than than the PM1 A/B status and enable registers 503 * in that different values can be written to the A/B registers. 504 * Most notably, the SLP_TYP bits can be different, as per the 505 * values returned from the _Sx predefined methods. 506 * 507 ******************************************************************************/ 508 509 ACPI_STATUS 510 AcpiHwWritePm1Control ( 511 UINT32 Pm1aControl, 512 UINT32 Pm1bControl) 513 { 514 ACPI_STATUS Status; 515 516 517 ACPI_FUNCTION_TRACE (HwWritePm1Control); 518 519 520 Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock); 521 if (ACPI_FAILURE (Status)) 522 { 523 return_ACPI_STATUS (Status); 524 } 525 526 if (AcpiGbl_FADT.XPm1bControlBlock.Address) 527 { 528 Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock); 529 } 530 return_ACPI_STATUS (Status); 531 } 532 533 534 /****************************************************************************** 535 * 536 * FUNCTION: AcpiHwRegisterRead 537 * 538 * PARAMETERS: RegisterId - ACPI Register ID 539 * ReturnValue - Where the register value is returned 540 * 541 * RETURN: Status and the value read. 542 * 543 * DESCRIPTION: Read from the specified ACPI register 544 * 545 ******************************************************************************/ 546 547 ACPI_STATUS 548 AcpiHwRegisterRead ( 549 UINT32 RegisterId, 550 UINT32 *ReturnValue) 551 { 552 UINT32 Value = 0; 553 ACPI_STATUS Status; 554 555 556 ACPI_FUNCTION_TRACE (HwRegisterRead); 557 558 559 switch (RegisterId) 560 { 561 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 562 563 Status = AcpiHwReadMultiple (&Value, 564 &AcpiGbl_XPm1aStatus, 565 &AcpiGbl_XPm1bStatus); 566 break; 567 568 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 569 570 Status = AcpiHwReadMultiple (&Value, 571 &AcpiGbl_XPm1aEnable, 572 &AcpiGbl_XPm1bEnable); 573 break; 574 575 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 576 577 Status = AcpiHwReadMultiple (&Value, 578 &AcpiGbl_FADT.XPm1aControlBlock, 579 &AcpiGbl_FADT.XPm1bControlBlock); 580 581 /* 582 * Zero the write-only bits. From the ACPI specification, "Hardware 583 * Write-Only Bits": "Upon reads to registers with write-only bits, 584 * software masks out all write-only bits." 585 */ 586 Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; 587 break; 588 589 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 590 591 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); 592 break; 593 594 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 595 596 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); 597 break; 598 599 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 600 601 Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); 602 break; 603 604 default: 605 606 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 607 RegisterId)); 608 Status = AE_BAD_PARAMETER; 609 break; 610 } 611 612 if (ACPI_SUCCESS (Status)) 613 { 614 *ReturnValue = Value; 615 } 616 617 return_ACPI_STATUS (Status); 618 } 619 620 621 /****************************************************************************** 622 * 623 * FUNCTION: AcpiHwRegisterWrite 624 * 625 * PARAMETERS: RegisterId - ACPI Register ID 626 * Value - The value to write 627 * 628 * RETURN: Status 629 * 630 * DESCRIPTION: Write to the specified ACPI register 631 * 632 * NOTE: In accordance with the ACPI specification, this function automatically 633 * preserves the value of the following bits, meaning that these bits cannot be 634 * changed via this interface: 635 * 636 * PM1_CONTROL[0] = SCI_EN 637 * PM1_CONTROL[9] 638 * PM1_STATUS[11] 639 * 640 * ACPI References: 641 * 1) Hardware Ignored Bits: When software writes to a register with ignored 642 * bit fields, it preserves the ignored bit fields 643 * 2) SCI_EN: OSPM always preserves this bit position 644 * 645 ******************************************************************************/ 646 647 ACPI_STATUS 648 AcpiHwRegisterWrite ( 649 UINT32 RegisterId, 650 UINT32 Value) 651 { 652 ACPI_STATUS Status; 653 UINT32 ReadValue; 654 655 656 ACPI_FUNCTION_TRACE (HwRegisterWrite); 657 658 659 switch (RegisterId) 660 { 661 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 662 /* 663 * Handle the "ignored" bit in PM1 Status. According to the ACPI 664 * specification, ignored bits are to be preserved when writing. 665 * Normally, this would mean a read/modify/write sequence. However, 666 * preserving a bit in the status register is different. Writing a 667 * one clears the status, and writing a zero preserves the status. 668 * Therefore, we must always write zero to the ignored bit. 669 * 670 * This behavior is clarified in the ACPI 4.0 specification. 671 */ 672 Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; 673 674 Status = AcpiHwWriteMultiple (Value, 675 &AcpiGbl_XPm1aStatus, 676 &AcpiGbl_XPm1bStatus); 677 break; 678 679 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 680 681 Status = AcpiHwWriteMultiple (Value, 682 &AcpiGbl_XPm1aEnable, 683 &AcpiGbl_XPm1bEnable); 684 break; 685 686 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 687 /* 688 * Perform a read first to preserve certain bits (per ACPI spec) 689 * Note: This includes SCI_EN, we never want to change this bit 690 */ 691 Status = AcpiHwReadMultiple (&ReadValue, 692 &AcpiGbl_FADT.XPm1aControlBlock, 693 &AcpiGbl_FADT.XPm1bControlBlock); 694 if (ACPI_FAILURE (Status)) 695 { 696 goto Exit; 697 } 698 699 /* Insert the bits to be preserved */ 700 701 ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); 702 703 /* Now we can write the data */ 704 705 Status = AcpiHwWriteMultiple (Value, 706 &AcpiGbl_FADT.XPm1aControlBlock, 707 &AcpiGbl_FADT.XPm1bControlBlock); 708 break; 709 710 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 711 /* 712 * For control registers, all reserved bits must be preserved, 713 * as per the ACPI spec. 714 */ 715 Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); 716 if (ACPI_FAILURE (Status)) 717 { 718 goto Exit; 719 } 720 721 /* Insert the bits to be preserved */ 722 723 ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); 724 725 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); 726 break; 727 728 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 729 730 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); 731 break; 732 733 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 734 735 /* SMI_CMD is currently always in IO space */ 736 737 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); 738 break; 739 740 default: 741 742 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 743 RegisterId)); 744 Status = AE_BAD_PARAMETER; 745 break; 746 } 747 748 Exit: 749 return_ACPI_STATUS (Status); 750 } 751 752 753 /****************************************************************************** 754 * 755 * FUNCTION: AcpiHwReadMultiple 756 * 757 * PARAMETERS: Value - Where the register value is returned 758 * RegisterA - First ACPI register (required) 759 * RegisterB - Second ACPI register (optional) 760 * 761 * RETURN: Status 762 * 763 * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) 764 * 765 ******************************************************************************/ 766 767 static ACPI_STATUS 768 AcpiHwReadMultiple ( 769 UINT32 *Value, 770 ACPI_GENERIC_ADDRESS *RegisterA, 771 ACPI_GENERIC_ADDRESS *RegisterB) 772 { 773 UINT32 ValueA = 0; 774 UINT32 ValueB = 0; 775 ACPI_STATUS Status; 776 777 778 /* The first register is always required */ 779 780 Status = AcpiHwRead (&ValueA, RegisterA); 781 if (ACPI_FAILURE (Status)) 782 { 783 return (Status); 784 } 785 786 /* Second register is optional */ 787 788 if (RegisterB->Address) 789 { 790 Status = AcpiHwRead (&ValueB, RegisterB); 791 if (ACPI_FAILURE (Status)) 792 { 793 return (Status); 794 } 795 } 796 797 /* 798 * OR the two return values together. No shifting or masking is necessary, 799 * because of how the PM1 registers are defined in the ACPI specification: 800 * 801 * "Although the bits can be split between the two register blocks (each 802 * register block has a unique pointer within the FADT), the bit positions 803 * are maintained. The register block with unimplemented bits (that is, 804 * those implemented in the other register block) always returns zeros, 805 * and writes have no side effects" 806 */ 807 *Value = (ValueA | ValueB); 808 return (AE_OK); 809 } 810 811 812 /****************************************************************************** 813 * 814 * FUNCTION: AcpiHwWriteMultiple 815 * 816 * PARAMETERS: Value - The value to write 817 * RegisterA - First ACPI register (required) 818 * RegisterB - Second ACPI register (optional) 819 * 820 * RETURN: Status 821 * 822 * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) 823 * 824 ******************************************************************************/ 825 826 static ACPI_STATUS 827 AcpiHwWriteMultiple ( 828 UINT32 Value, 829 ACPI_GENERIC_ADDRESS *RegisterA, 830 ACPI_GENERIC_ADDRESS *RegisterB) 831 { 832 ACPI_STATUS Status; 833 834 835 /* The first register is always required */ 836 837 Status = AcpiHwWrite (Value, RegisterA); 838 if (ACPI_FAILURE (Status)) 839 { 840 return (Status); 841 } 842 843 /* 844 * Second register is optional 845 * 846 * No bit shifting or clearing is necessary, because of how the PM1 847 * registers are defined in the ACPI specification: 848 * 849 * "Although the bits can be split between the two register blocks (each 850 * register block has a unique pointer within the FADT), the bit positions 851 * are maintained. The register block with unimplemented bits (that is, 852 * those implemented in the other register block) always returns zeros, 853 * and writes have no side effects" 854 */ 855 if (RegisterB->Address) 856 { 857 Status = AcpiHwWrite (Value, RegisterB); 858 } 859 860 return (Status); 861 } 862 863 #endif /* !ACPI_REDUCED_HARDWARE */ 864