Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /*******************************************************************************
0003  *
0004  * Module Name: hwregs - Read/write access functions for the various ACPI
0005  *                       control and status registers.
0006  *
0007  ******************************************************************************/
0008 
0009 #include <acpi/acpi.h>
0010 #include "accommon.h"
0011 #include "acevents.h"
0012 
0013 #define _COMPONENT          ACPI_HARDWARE
0014 ACPI_MODULE_NAME("hwregs")
0015 
0016 #if (!ACPI_REDUCED_HARDWARE)
0017 /* Local Prototypes */
0018 static u8
0019 acpi_hw_get_access_bit_width(u64 address,
0020                  struct acpi_generic_address *reg,
0021                  u8 max_bit_width);
0022 
0023 static acpi_status
0024 acpi_hw_read_multiple(u32 *value,
0025               struct acpi_generic_address *register_a,
0026               struct acpi_generic_address *register_b);
0027 
0028 static acpi_status
0029 acpi_hw_write_multiple(u32 value,
0030                struct acpi_generic_address *register_a,
0031                struct acpi_generic_address *register_b);
0032 
0033 #endif              /* !ACPI_REDUCED_HARDWARE */
0034 
0035 /******************************************************************************
0036  *
0037  * FUNCTION:    acpi_hw_get_access_bit_width
0038  *
0039  * PARAMETERS:  address             - GAS register address
0040  *              reg                 - GAS register structure
0041  *              max_bit_width       - Max bit_width supported (32 or 64)
0042  *
0043  * RETURN:      Status
0044  *
0045  * DESCRIPTION: Obtain optimal access bit width
0046  *
0047  ******************************************************************************/
0048 
0049 static u8
0050 acpi_hw_get_access_bit_width(u64 address,
0051                  struct acpi_generic_address *reg, u8 max_bit_width)
0052 {
0053     u8 access_bit_width;
0054 
0055     /*
0056      * GAS format "register", used by FADT:
0057      *  1. Detected if bit_offset is 0 and bit_width is 8/16/32/64;
0058      *  2. access_size field is ignored and bit_width field is used for
0059      *     determining the boundary of the IO accesses.
0060      * GAS format "region", used by APEI registers:
0061      *  1. Detected if bit_offset is not 0 or bit_width is not 8/16/32/64;
0062      *  2. access_size field is used for determining the boundary of the
0063      *     IO accesses;
0064      *  3. bit_offset/bit_width fields are used to describe the "region".
0065      *
0066      * Note: This algorithm assumes that the "Address" fields should always
0067      *       contain aligned values.
0068      */
0069     if (!reg->bit_offset && reg->bit_width &&
0070         ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
0071         ACPI_IS_ALIGNED(reg->bit_width, 8)) {
0072         access_bit_width = reg->bit_width;
0073     } else if (reg->access_width) {
0074         access_bit_width = ACPI_ACCESS_BIT_WIDTH(reg->access_width);
0075     } else {
0076         access_bit_width =
0077             ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset +
0078                          reg->bit_width);
0079         if (access_bit_width <= 8) {
0080             access_bit_width = 8;
0081         } else {
0082             while (!ACPI_IS_ALIGNED(address, access_bit_width >> 3)) {
0083                 access_bit_width >>= 1;
0084             }
0085         }
0086     }
0087 
0088     /* Maximum IO port access bit width is 32 */
0089 
0090     if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
0091         max_bit_width = 32;
0092     }
0093 
0094     /*
0095      * Return access width according to the requested maximum access bit width,
0096      * as the caller should know the format of the register and may enforce
0097      * a 32-bit accesses.
0098      */
0099     if (access_bit_width < max_bit_width) {
0100         return (access_bit_width);
0101     }
0102     return (max_bit_width);
0103 }
0104 
0105 /******************************************************************************
0106  *
0107  * FUNCTION:    acpi_hw_validate_register
0108  *
0109  * PARAMETERS:  reg                 - GAS register structure
0110  *              max_bit_width       - Max bit_width supported (32 or 64)
0111  *              address             - Pointer to where the gas->address
0112  *                                    is returned
0113  *
0114  * RETURN:      Status
0115  *
0116  * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
0117  *              pointer, Address, space_id, bit_width, and bit_offset.
0118  *
0119  ******************************************************************************/
0120 
0121 acpi_status
0122 acpi_hw_validate_register(struct acpi_generic_address *reg,
0123               u8 max_bit_width, u64 *address)
0124 {
0125     u8 bit_width;
0126     u8 access_width;
0127 
0128     /* Must have a valid pointer to a GAS structure */
0129 
0130     if (!reg) {
0131         return (AE_BAD_PARAMETER);
0132     }
0133 
0134     /*
0135      * Copy the target address. This handles possible alignment issues.
0136      * Address must not be null. A null address also indicates an optional
0137      * ACPI register that is not supported, so no error message.
0138      */
0139     ACPI_MOVE_64_TO_64(address, &reg->address);
0140     if (!(*address)) {
0141         return (AE_BAD_ADDRESS);
0142     }
0143 
0144     /* Validate the space_ID */
0145 
0146     if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
0147         (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
0148         ACPI_ERROR((AE_INFO,
0149                 "Unsupported address space: 0x%X", reg->space_id));
0150         return (AE_SUPPORT);
0151     }
0152 
0153     /* Validate the access_width */
0154 
0155     if (reg->access_width > 4) {
0156         ACPI_ERROR((AE_INFO,
0157                 "Unsupported register access width: 0x%X",
0158                 reg->access_width));
0159         return (AE_SUPPORT);
0160     }
0161 
0162     /* Validate the bit_width, convert access_width into number of bits */
0163 
0164     access_width =
0165         acpi_hw_get_access_bit_width(*address, reg, max_bit_width);
0166     bit_width =
0167         ACPI_ROUND_UP(reg->bit_offset + reg->bit_width, access_width);
0168     if (max_bit_width < bit_width) {
0169         ACPI_WARNING((AE_INFO,
0170                   "Requested bit width 0x%X is smaller than register bit width 0x%X",
0171                   max_bit_width, bit_width));
0172         return (AE_SUPPORT);
0173     }
0174 
0175     return (AE_OK);
0176 }
0177 
0178 /******************************************************************************
0179  *
0180  * FUNCTION:    acpi_hw_read
0181  *
0182  * PARAMETERS:  value               - Where the value is returned
0183  *              reg                 - GAS register structure
0184  *
0185  * RETURN:      Status
0186  *
0187  * DESCRIPTION: Read from either memory or IO space. This is a 64-bit max
0188  *              version of acpi_read.
0189  *
0190  * LIMITATIONS: <These limitations also apply to acpi_hw_write>
0191  *      space_ID must be system_memory or system_IO.
0192  *
0193  ******************************************************************************/
0194 
0195 acpi_status acpi_hw_read(u64 *value, struct acpi_generic_address *reg)
0196 {
0197     u64 address;
0198     u8 access_width;
0199     u32 bit_width;
0200     u8 bit_offset;
0201     u64 value64;
0202     u32 value32;
0203     u8 index;
0204     acpi_status status;
0205 
0206     ACPI_FUNCTION_NAME(hw_read);
0207 
0208     /* Validate contents of the GAS register */
0209 
0210     status = acpi_hw_validate_register(reg, 64, &address);
0211     if (ACPI_FAILURE(status)) {
0212         return (status);
0213     }
0214 
0215     /*
0216      * Initialize entire 64-bit return value to zero, convert access_width
0217      * into number of bits based
0218      */
0219     *value = 0;
0220     access_width = acpi_hw_get_access_bit_width(address, reg, 64);
0221     bit_width = reg->bit_offset + reg->bit_width;
0222     bit_offset = reg->bit_offset;
0223 
0224     /*
0225      * Two address spaces supported: Memory or IO. PCI_Config is
0226      * not supported here because the GAS structure is insufficient
0227      */
0228     index = 0;
0229     while (bit_width) {
0230         if (bit_offset >= access_width) {
0231             value64 = 0;
0232             bit_offset -= access_width;
0233         } else {
0234             if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
0235                 status =
0236                     acpi_os_read_memory((acpi_physical_address)
0237                             address +
0238                             index *
0239                             ACPI_DIV_8
0240                             (access_width),
0241                             &value64, access_width);
0242             } else {    /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
0243 
0244                 status = acpi_hw_read_port((acpi_io_address)
0245                                address +
0246                                index *
0247                                ACPI_DIV_8
0248                                (access_width),
0249                                &value32,
0250                                access_width);
0251                 value64 = (u64)value32;
0252             }
0253         }
0254 
0255         /*
0256          * Use offset style bit writes because "Index * AccessWidth" is
0257          * ensured to be less than 64-bits by acpi_hw_validate_register().
0258          */
0259         ACPI_SET_BITS(value, index * access_width,
0260                   ACPI_MASK_BITS_ABOVE_64(access_width), value64);
0261 
0262         bit_width -=
0263             bit_width > access_width ? access_width : bit_width;
0264         index++;
0265     }
0266 
0267     ACPI_DEBUG_PRINT((ACPI_DB_IO,
0268               "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
0269               ACPI_FORMAT_UINT64(*value), access_width,
0270               ACPI_FORMAT_UINT64(address),
0271               acpi_ut_get_region_name(reg->space_id)));
0272 
0273     return (status);
0274 }
0275 
0276 /******************************************************************************
0277  *
0278  * FUNCTION:    acpi_hw_write
0279  *
0280  * PARAMETERS:  value               - Value to be written
0281  *              reg                 - GAS register structure
0282  *
0283  * RETURN:      Status
0284  *
0285  * DESCRIPTION: Write to either memory or IO space. This is a 64-bit max
0286  *              version of acpi_write.
0287  *
0288  ******************************************************************************/
0289 
0290 acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg)
0291 {
0292     u64 address;
0293     u8 access_width;
0294     u32 bit_width;
0295     u8 bit_offset;
0296     u64 value64;
0297     u8 index;
0298     acpi_status status;
0299 
0300     ACPI_FUNCTION_NAME(hw_write);
0301 
0302     /* Validate contents of the GAS register */
0303 
0304     status = acpi_hw_validate_register(reg, 64, &address);
0305     if (ACPI_FAILURE(status)) {
0306         return (status);
0307     }
0308 
0309     /* Convert access_width into number of bits based */
0310 
0311     access_width = acpi_hw_get_access_bit_width(address, reg, 64);
0312     bit_width = reg->bit_offset + reg->bit_width;
0313     bit_offset = reg->bit_offset;
0314 
0315     /*
0316      * Two address spaces supported: Memory or IO. PCI_Config is
0317      * not supported here because the GAS structure is insufficient
0318      */
0319     index = 0;
0320     while (bit_width) {
0321         /*
0322          * Use offset style bit reads because "Index * AccessWidth" is
0323          * ensured to be less than 64-bits by acpi_hw_validate_register().
0324          */
0325         value64 = ACPI_GET_BITS(&value, index * access_width,
0326                     ACPI_MASK_BITS_ABOVE_64(access_width));
0327 
0328         if (bit_offset >= access_width) {
0329             bit_offset -= access_width;
0330         } else {
0331             if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
0332                 status =
0333                     acpi_os_write_memory((acpi_physical_address)
0334                              address +
0335                              index *
0336                              ACPI_DIV_8
0337                              (access_width),
0338                              value64, access_width);
0339             } else {    /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
0340 
0341                 status = acpi_hw_write_port((acpi_io_address)
0342                                 address +
0343                                 index *
0344                                 ACPI_DIV_8
0345                                 (access_width),
0346                                 (u32)value64,
0347                                 access_width);
0348             }
0349         }
0350 
0351         /*
0352          * Index * access_width is ensured to be less than 32-bits by
0353          * acpi_hw_validate_register().
0354          */
0355         bit_width -=
0356             bit_width > access_width ? access_width : bit_width;
0357         index++;
0358     }
0359 
0360     ACPI_DEBUG_PRINT((ACPI_DB_IO,
0361               "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
0362               ACPI_FORMAT_UINT64(value), access_width,
0363               ACPI_FORMAT_UINT64(address),
0364               acpi_ut_get_region_name(reg->space_id)));
0365 
0366     return (status);
0367 }
0368 
0369 #if (!ACPI_REDUCED_HARDWARE)
0370 /*******************************************************************************
0371  *
0372  * FUNCTION:    acpi_hw_clear_acpi_status
0373  *
0374  * PARAMETERS:  None
0375  *
0376  * RETURN:      Status
0377  *
0378  * DESCRIPTION: Clears all fixed and general purpose status bits
0379  *
0380  ******************************************************************************/
0381 
0382 acpi_status acpi_hw_clear_acpi_status(void)
0383 {
0384     acpi_status status;
0385     acpi_cpu_flags lock_flags = 0;
0386 
0387     ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
0388 
0389     ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
0390               ACPI_BITMASK_ALL_FIXED_STATUS,
0391               ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address)));
0392 
0393     lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock);
0394 
0395     /* Clear the fixed events in PM1 A/B */
0396 
0397     status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
0398                     ACPI_BITMASK_ALL_FIXED_STATUS);
0399 
0400     acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags);
0401 
0402     if (ACPI_FAILURE(status)) {
0403         goto exit;
0404     }
0405 
0406     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
0407 
0408     status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
0409 
0410 exit:
0411     return_ACPI_STATUS(status);
0412 }
0413 
0414 /*******************************************************************************
0415  *
0416  * FUNCTION:    acpi_hw_get_bit_register_info
0417  *
0418  * PARAMETERS:  register_id         - Index of ACPI Register to access
0419  *
0420  * RETURN:      The bitmask to be used when accessing the register
0421  *
0422  * DESCRIPTION: Map register_id into a register bitmask.
0423  *
0424  ******************************************************************************/
0425 
0426 struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
0427 {
0428     ACPI_FUNCTION_ENTRY();
0429 
0430     if (register_id > ACPI_BITREG_MAX) {
0431         ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: 0x%X",
0432                 register_id));
0433         return (NULL);
0434     }
0435 
0436     return (&acpi_gbl_bit_register_info[register_id]);
0437 }
0438 
0439 /******************************************************************************
0440  *
0441  * FUNCTION:    acpi_hw_write_pm1_control
0442  *
0443  * PARAMETERS:  pm1a_control        - Value to be written to PM1A control
0444  *              pm1b_control        - Value to be written to PM1B control
0445  *
0446  * RETURN:      Status
0447  *
0448  * DESCRIPTION: Write the PM1 A/B control registers. These registers are
0449  *              different than the PM1 A/B status and enable registers
0450  *              in that different values can be written to the A/B registers.
0451  *              Most notably, the SLP_TYP bits can be different, as per the
0452  *              values returned from the _Sx predefined methods.
0453  *
0454  ******************************************************************************/
0455 
0456 acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
0457 {
0458     acpi_status status;
0459 
0460     ACPI_FUNCTION_TRACE(hw_write_pm1_control);
0461 
0462     status =
0463         acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block);
0464     if (ACPI_FAILURE(status)) {
0465         return_ACPI_STATUS(status);
0466     }
0467 
0468     if (acpi_gbl_FADT.xpm1b_control_block.address) {
0469         status =
0470             acpi_hw_write(pm1b_control,
0471                   &acpi_gbl_FADT.xpm1b_control_block);
0472     }
0473     return_ACPI_STATUS(status);
0474 }
0475 
0476 /******************************************************************************
0477  *
0478  * FUNCTION:    acpi_hw_register_read
0479  *
0480  * PARAMETERS:  register_id         - ACPI Register ID
0481  *              return_value        - Where the register value is returned
0482  *
0483  * RETURN:      Status and the value read.
0484  *
0485  * DESCRIPTION: Read from the specified ACPI register
0486  *
0487  ******************************************************************************/
0488 acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
0489 {
0490     u32 value = 0;
0491     u64 value64;
0492     acpi_status status;
0493 
0494     ACPI_FUNCTION_TRACE(hw_register_read);
0495 
0496     switch (register_id) {
0497     case ACPI_REGISTER_PM1_STATUS:  /* PM1 A/B: 16-bit access each */
0498 
0499         status = acpi_hw_read_multiple(&value,
0500                            &acpi_gbl_xpm1a_status,
0501                            &acpi_gbl_xpm1b_status);
0502         break;
0503 
0504     case ACPI_REGISTER_PM1_ENABLE:  /* PM1 A/B: 16-bit access each */
0505 
0506         status = acpi_hw_read_multiple(&value,
0507                            &acpi_gbl_xpm1a_enable,
0508                            &acpi_gbl_xpm1b_enable);
0509         break;
0510 
0511     case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
0512 
0513         status = acpi_hw_read_multiple(&value,
0514                            &acpi_gbl_FADT.
0515                            xpm1a_control_block,
0516                            &acpi_gbl_FADT.
0517                            xpm1b_control_block);
0518 
0519         /*
0520          * Zero the write-only bits. From the ACPI specification, "Hardware
0521          * Write-Only Bits": "Upon reads to registers with write-only bits,
0522          * software masks out all write-only bits."
0523          */
0524         value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
0525         break;
0526 
0527     case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
0528 
0529         status =
0530             acpi_hw_read(&value64, &acpi_gbl_FADT.xpm2_control_block);
0531         if (ACPI_SUCCESS(status)) {
0532             value = (u32)value64;
0533         }
0534         break;
0535 
0536     case ACPI_REGISTER_PM_TIMER:    /* 32-bit access */
0537 
0538         status = acpi_hw_read(&value64, &acpi_gbl_FADT.xpm_timer_block);
0539         if (ACPI_SUCCESS(status)) {
0540             value = (u32)value64;
0541         }
0542 
0543         break;
0544 
0545     case ACPI_REGISTER_SMI_COMMAND_BLOCK:   /* 8-bit access */
0546 
0547         status =
0548             acpi_hw_read_port(acpi_gbl_FADT.smi_command, &value, 8);
0549         break;
0550 
0551     default:
0552 
0553         ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
0554         status = AE_BAD_PARAMETER;
0555         break;
0556     }
0557 
0558     if (ACPI_SUCCESS(status)) {
0559         *return_value = (u32)value;
0560     }
0561 
0562     return_ACPI_STATUS(status);
0563 }
0564 
0565 /******************************************************************************
0566  *
0567  * FUNCTION:    acpi_hw_register_write
0568  *
0569  * PARAMETERS:  register_id         - ACPI Register ID
0570  *              value               - The value to write
0571  *
0572  * RETURN:      Status
0573  *
0574  * DESCRIPTION: Write to the specified ACPI register
0575  *
0576  * NOTE: In accordance with the ACPI specification, this function automatically
0577  * preserves the value of the following bits, meaning that these bits cannot be
0578  * changed via this interface:
0579  *
0580  * PM1_CONTROL[0] = SCI_EN
0581  * PM1_CONTROL[9]
0582  * PM1_STATUS[11]
0583  *
0584  * ACPI References:
0585  * 1) Hardware Ignored Bits: When software writes to a register with ignored
0586  *      bit fields, it preserves the ignored bit fields
0587  * 2) SCI_EN: OSPM always preserves this bit position
0588  *
0589  ******************************************************************************/
0590 
0591 acpi_status acpi_hw_register_write(u32 register_id, u32 value)
0592 {
0593     acpi_status status;
0594     u32 read_value;
0595     u64 read_value64;
0596 
0597     ACPI_FUNCTION_TRACE(hw_register_write);
0598 
0599     switch (register_id) {
0600     case ACPI_REGISTER_PM1_STATUS:  /* PM1 A/B: 16-bit access each */
0601         /*
0602          * Handle the "ignored" bit in PM1 Status. According to the ACPI
0603          * specification, ignored bits are to be preserved when writing.
0604          * Normally, this would mean a read/modify/write sequence. However,
0605          * preserving a bit in the status register is different. Writing a
0606          * one clears the status, and writing a zero preserves the status.
0607          * Therefore, we must always write zero to the ignored bit.
0608          *
0609          * This behavior is clarified in the ACPI 4.0 specification.
0610          */
0611         value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
0612 
0613         status = acpi_hw_write_multiple(value,
0614                         &acpi_gbl_xpm1a_status,
0615                         &acpi_gbl_xpm1b_status);
0616         break;
0617 
0618     case ACPI_REGISTER_PM1_ENABLE:  /* PM1 A/B: 16-bit access each */
0619 
0620         status = acpi_hw_write_multiple(value,
0621                         &acpi_gbl_xpm1a_enable,
0622                         &acpi_gbl_xpm1b_enable);
0623         break;
0624 
0625     case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
0626         /*
0627          * Perform a read first to preserve certain bits (per ACPI spec)
0628          * Note: This includes SCI_EN, we never want to change this bit
0629          */
0630         status = acpi_hw_read_multiple(&read_value,
0631                            &acpi_gbl_FADT.
0632                            xpm1a_control_block,
0633                            &acpi_gbl_FADT.
0634                            xpm1b_control_block);
0635         if (ACPI_FAILURE(status)) {
0636             goto exit;
0637         }
0638 
0639         /* Insert the bits to be preserved */
0640 
0641         ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
0642                  read_value);
0643 
0644         /* Now we can write the data */
0645 
0646         status = acpi_hw_write_multiple(value,
0647                         &acpi_gbl_FADT.
0648                         xpm1a_control_block,
0649                         &acpi_gbl_FADT.
0650                         xpm1b_control_block);
0651         break;
0652 
0653     case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
0654         /*
0655          * For control registers, all reserved bits must be preserved,
0656          * as per the ACPI spec.
0657          */
0658         status =
0659             acpi_hw_read(&read_value64,
0660                  &acpi_gbl_FADT.xpm2_control_block);
0661         if (ACPI_FAILURE(status)) {
0662             goto exit;
0663         }
0664         read_value = (u32)read_value64;
0665 
0666         /* Insert the bits to be preserved */
0667 
0668         ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS,
0669                  read_value);
0670 
0671         status =
0672             acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block);
0673         break;
0674 
0675     case ACPI_REGISTER_PM_TIMER:    /* 32-bit access */
0676 
0677         status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block);
0678         break;
0679 
0680     case ACPI_REGISTER_SMI_COMMAND_BLOCK:   /* 8-bit access */
0681 
0682         /* SMI_CMD is currently always in IO space */
0683 
0684         status =
0685             acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8);
0686         break;
0687 
0688     default:
0689 
0690         ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
0691         status = AE_BAD_PARAMETER;
0692         break;
0693     }
0694 
0695 exit:
0696     return_ACPI_STATUS(status);
0697 }
0698 
0699 /******************************************************************************
0700  *
0701  * FUNCTION:    acpi_hw_read_multiple
0702  *
0703  * PARAMETERS:  value               - Where the register value is returned
0704  *              register_a           - First ACPI register (required)
0705  *              register_b           - Second ACPI register (optional)
0706  *
0707  * RETURN:      Status
0708  *
0709  * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
0710  *
0711  ******************************************************************************/
0712 
0713 static acpi_status
0714 acpi_hw_read_multiple(u32 *value,
0715               struct acpi_generic_address *register_a,
0716               struct acpi_generic_address *register_b)
0717 {
0718     u32 value_a = 0;
0719     u32 value_b = 0;
0720     u64 value64;
0721     acpi_status status;
0722 
0723     /* The first register is always required */
0724 
0725     status = acpi_hw_read(&value64, register_a);
0726     if (ACPI_FAILURE(status)) {
0727         return (status);
0728     }
0729     value_a = (u32)value64;
0730 
0731     /* Second register is optional */
0732 
0733     if (register_b->address) {
0734         status = acpi_hw_read(&value64, register_b);
0735         if (ACPI_FAILURE(status)) {
0736             return (status);
0737         }
0738         value_b = (u32)value64;
0739     }
0740 
0741     /*
0742      * OR the two return values together. No shifting or masking is necessary,
0743      * because of how the PM1 registers are defined in the ACPI specification:
0744      *
0745      * "Although the bits can be split between the two register blocks (each
0746      * register block has a unique pointer within the FADT), the bit positions
0747      * are maintained. The register block with unimplemented bits (that is,
0748      * those implemented in the other register block) always returns zeros,
0749      * and writes have no side effects"
0750      */
0751     *value = (value_a | value_b);
0752     return (AE_OK);
0753 }
0754 
0755 /******************************************************************************
0756  *
0757  * FUNCTION:    acpi_hw_write_multiple
0758  *
0759  * PARAMETERS:  value               - The value to write
0760  *              register_a           - First ACPI register (required)
0761  *              register_b           - Second ACPI register (optional)
0762  *
0763  * RETURN:      Status
0764  *
0765  * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
0766  *
0767  ******************************************************************************/
0768 
0769 static acpi_status
0770 acpi_hw_write_multiple(u32 value,
0771                struct acpi_generic_address *register_a,
0772                struct acpi_generic_address *register_b)
0773 {
0774     acpi_status status;
0775 
0776     /* The first register is always required */
0777 
0778     status = acpi_hw_write(value, register_a);
0779     if (ACPI_FAILURE(status)) {
0780         return (status);
0781     }
0782 
0783     /*
0784      * Second register is optional
0785      *
0786      * No bit shifting or clearing is necessary, because of how the PM1
0787      * registers are defined in the ACPI specification:
0788      *
0789      * "Although the bits can be split between the two register blocks (each
0790      * register block has a unique pointer within the FADT), the bit positions
0791      * are maintained. The register block with unimplemented bits (that is,
0792      * those implemented in the other register block) always returns zeros,
0793      * and writes have no side effects"
0794      */
0795     if (register_b->address) {
0796         status = acpi_hw_write(value, register_b);
0797     }
0798 
0799     return (status);
0800 }
0801 
0802 #endif              /* !ACPI_REDUCED_HARDWARE */