cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hwregs.c (22492B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/*******************************************************************************
      3 *
      4 * Module Name: hwregs - Read/write access functions for the various ACPI
      5 *                       control and status registers.
      6 *
      7 ******************************************************************************/
      8
      9#include <acpi/acpi.h>
     10#include "accommon.h"
     11#include "acevents.h"
     12
     13#define _COMPONENT          ACPI_HARDWARE
     14ACPI_MODULE_NAME("hwregs")
     15
     16#if (!ACPI_REDUCED_HARDWARE)
     17/* Local Prototypes */
     18static u8
     19acpi_hw_get_access_bit_width(u64 address,
     20			     struct acpi_generic_address *reg,
     21			     u8 max_bit_width);
     22
     23static acpi_status
     24acpi_hw_read_multiple(u32 *value,
     25		      struct acpi_generic_address *register_a,
     26		      struct acpi_generic_address *register_b);
     27
     28static acpi_status
     29acpi_hw_write_multiple(u32 value,
     30		       struct acpi_generic_address *register_a,
     31		       struct acpi_generic_address *register_b);
     32
     33#endif				/* !ACPI_REDUCED_HARDWARE */
     34
     35/******************************************************************************
     36 *
     37 * FUNCTION:    acpi_hw_get_access_bit_width
     38 *
     39 * PARAMETERS:  address             - GAS register address
     40 *              reg                 - GAS register structure
     41 *              max_bit_width       - Max bit_width supported (32 or 64)
     42 *
     43 * RETURN:      Status
     44 *
     45 * DESCRIPTION: Obtain optimal access bit width
     46 *
     47 ******************************************************************************/
     48
     49static u8
     50acpi_hw_get_access_bit_width(u64 address,
     51			     struct acpi_generic_address *reg, u8 max_bit_width)
     52{
     53	u8 access_bit_width;
     54
     55	/*
     56	 * GAS format "register", used by FADT:
     57	 *  1. Detected if bit_offset is 0 and bit_width is 8/16/32/64;
     58	 *  2. access_size field is ignored and bit_width field is used for
     59	 *     determining the boundary of the IO accesses.
     60	 * GAS format "region", used by APEI registers:
     61	 *  1. Detected if bit_offset is not 0 or bit_width is not 8/16/32/64;
     62	 *  2. access_size field is used for determining the boundary of the
     63	 *     IO accesses;
     64	 *  3. bit_offset/bit_width fields are used to describe the "region".
     65	 *
     66	 * Note: This algorithm assumes that the "Address" fields should always
     67	 *       contain aligned values.
     68	 */
     69	if (!reg->bit_offset && reg->bit_width &&
     70	    ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
     71	    ACPI_IS_ALIGNED(reg->bit_width, 8)) {
     72		access_bit_width = reg->bit_width;
     73	} else if (reg->access_width) {
     74		access_bit_width = ACPI_ACCESS_BIT_WIDTH(reg->access_width);
     75	} else {
     76		access_bit_width =
     77		    ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset +
     78						 reg->bit_width);
     79		if (access_bit_width <= 8) {
     80			access_bit_width = 8;
     81		} else {
     82			while (!ACPI_IS_ALIGNED(address, access_bit_width >> 3)) {
     83				access_bit_width >>= 1;
     84			}
     85		}
     86	}
     87
     88	/* Maximum IO port access bit width is 32 */
     89
     90	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
     91		max_bit_width = 32;
     92	}
     93
     94	/*
     95	 * Return access width according to the requested maximum access bit width,
     96	 * as the caller should know the format of the register and may enforce
     97	 * a 32-bit accesses.
     98	 */
     99	if (access_bit_width < max_bit_width) {
    100		return (access_bit_width);
    101	}
    102	return (max_bit_width);
    103}
    104
    105/******************************************************************************
    106 *
    107 * FUNCTION:    acpi_hw_validate_register
    108 *
    109 * PARAMETERS:  reg                 - GAS register structure
    110 *              max_bit_width       - Max bit_width supported (32 or 64)
    111 *              address             - Pointer to where the gas->address
    112 *                                    is returned
    113 *
    114 * RETURN:      Status
    115 *
    116 * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
    117 *              pointer, Address, space_id, bit_width, and bit_offset.
    118 *
    119 ******************************************************************************/
    120
    121acpi_status
    122acpi_hw_validate_register(struct acpi_generic_address *reg,
    123			  u8 max_bit_width, u64 *address)
    124{
    125	u8 bit_width;
    126	u8 access_width;
    127
    128	/* Must have a valid pointer to a GAS structure */
    129
    130	if (!reg) {
    131		return (AE_BAD_PARAMETER);
    132	}
    133
    134	/*
    135	 * Copy the target address. This handles possible alignment issues.
    136	 * Address must not be null. A null address also indicates an optional
    137	 * ACPI register that is not supported, so no error message.
    138	 */
    139	ACPI_MOVE_64_TO_64(address, &reg->address);
    140	if (!(*address)) {
    141		return (AE_BAD_ADDRESS);
    142	}
    143
    144	/* Validate the space_ID */
    145
    146	if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
    147	    (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
    148		ACPI_ERROR((AE_INFO,
    149			    "Unsupported address space: 0x%X", reg->space_id));
    150		return (AE_SUPPORT);
    151	}
    152
    153	/* Validate the access_width */
    154
    155	if (reg->access_width > 4) {
    156		ACPI_ERROR((AE_INFO,
    157			    "Unsupported register access width: 0x%X",
    158			    reg->access_width));
    159		return (AE_SUPPORT);
    160	}
    161
    162	/* Validate the bit_width, convert access_width into number of bits */
    163
    164	access_width =
    165	    acpi_hw_get_access_bit_width(*address, reg, max_bit_width);
    166	bit_width =
    167	    ACPI_ROUND_UP(reg->bit_offset + reg->bit_width, access_width);
    168	if (max_bit_width < bit_width) {
    169		ACPI_WARNING((AE_INFO,
    170			      "Requested bit width 0x%X is smaller than register bit width 0x%X",
    171			      max_bit_width, bit_width));
    172		return (AE_SUPPORT);
    173	}
    174
    175	return (AE_OK);
    176}
    177
    178/******************************************************************************
    179 *
    180 * FUNCTION:    acpi_hw_read
    181 *
    182 * PARAMETERS:  value               - Where the value is returned
    183 *              reg                 - GAS register structure
    184 *
    185 * RETURN:      Status
    186 *
    187 * DESCRIPTION: Read from either memory or IO space. This is a 64-bit max
    188 *              version of acpi_read.
    189 *
    190 * LIMITATIONS: <These limitations also apply to acpi_hw_write>
    191 *      space_ID must be system_memory or system_IO.
    192 *
    193 ******************************************************************************/
    194
    195acpi_status acpi_hw_read(u64 *value, struct acpi_generic_address *reg)
    196{
    197	u64 address;
    198	u8 access_width;
    199	u32 bit_width;
    200	u8 bit_offset;
    201	u64 value64;
    202	u32 value32;
    203	u8 index;
    204	acpi_status status;
    205
    206	ACPI_FUNCTION_NAME(hw_read);
    207
    208	/* Validate contents of the GAS register */
    209
    210	status = acpi_hw_validate_register(reg, 64, &address);
    211	if (ACPI_FAILURE(status)) {
    212		return (status);
    213	}
    214
    215	/*
    216	 * Initialize entire 64-bit return value to zero, convert access_width
    217	 * into number of bits based
    218	 */
    219	*value = 0;
    220	access_width = acpi_hw_get_access_bit_width(address, reg, 64);
    221	bit_width = reg->bit_offset + reg->bit_width;
    222	bit_offset = reg->bit_offset;
    223
    224	/*
    225	 * Two address spaces supported: Memory or IO. PCI_Config is
    226	 * not supported here because the GAS structure is insufficient
    227	 */
    228	index = 0;
    229	while (bit_width) {
    230		if (bit_offset >= access_width) {
    231			value64 = 0;
    232			bit_offset -= access_width;
    233		} else {
    234			if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
    235				status =
    236				    acpi_os_read_memory((acpi_physical_address)
    237							address +
    238							index *
    239							ACPI_DIV_8
    240							(access_width),
    241							&value64, access_width);
    242			} else {	/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
    243
    244				status = acpi_hw_read_port((acpi_io_address)
    245							   address +
    246							   index *
    247							   ACPI_DIV_8
    248							   (access_width),
    249							   &value32,
    250							   access_width);
    251				value64 = (u64)value32;
    252			}
    253		}
    254
    255		/*
    256		 * Use offset style bit writes because "Index * AccessWidth" is
    257		 * ensured to be less than 64-bits by acpi_hw_validate_register().
    258		 */
    259		ACPI_SET_BITS(value, index * access_width,
    260			      ACPI_MASK_BITS_ABOVE_64(access_width), value64);
    261
    262		bit_width -=
    263		    bit_width > access_width ? access_width : bit_width;
    264		index++;
    265	}
    266
    267	ACPI_DEBUG_PRINT((ACPI_DB_IO,
    268			  "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
    269			  ACPI_FORMAT_UINT64(*value), access_width,
    270			  ACPI_FORMAT_UINT64(address),
    271			  acpi_ut_get_region_name(reg->space_id)));
    272
    273	return (status);
    274}
    275
    276/******************************************************************************
    277 *
    278 * FUNCTION:    acpi_hw_write
    279 *
    280 * PARAMETERS:  value               - Value to be written
    281 *              reg                 - GAS register structure
    282 *
    283 * RETURN:      Status
    284 *
    285 * DESCRIPTION: Write to either memory or IO space. This is a 64-bit max
    286 *              version of acpi_write.
    287 *
    288 ******************************************************************************/
    289
    290acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg)
    291{
    292	u64 address;
    293	u8 access_width;
    294	u32 bit_width;
    295	u8 bit_offset;
    296	u64 value64;
    297	u8 index;
    298	acpi_status status;
    299
    300	ACPI_FUNCTION_NAME(hw_write);
    301
    302	/* Validate contents of the GAS register */
    303
    304	status = acpi_hw_validate_register(reg, 64, &address);
    305	if (ACPI_FAILURE(status)) {
    306		return (status);
    307	}
    308
    309	/* Convert access_width into number of bits based */
    310
    311	access_width = acpi_hw_get_access_bit_width(address, reg, 64);
    312	bit_width = reg->bit_offset + reg->bit_width;
    313	bit_offset = reg->bit_offset;
    314
    315	/*
    316	 * Two address spaces supported: Memory or IO. PCI_Config is
    317	 * not supported here because the GAS structure is insufficient
    318	 */
    319	index = 0;
    320	while (bit_width) {
    321		/*
    322		 * Use offset style bit reads because "Index * AccessWidth" is
    323		 * ensured to be less than 64-bits by acpi_hw_validate_register().
    324		 */
    325		value64 = ACPI_GET_BITS(&value, index * access_width,
    326					ACPI_MASK_BITS_ABOVE_64(access_width));
    327
    328		if (bit_offset >= access_width) {
    329			bit_offset -= access_width;
    330		} else {
    331			if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
    332				status =
    333				    acpi_os_write_memory((acpi_physical_address)
    334							 address +
    335							 index *
    336							 ACPI_DIV_8
    337							 (access_width),
    338							 value64, access_width);
    339			} else {	/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
    340
    341				status = acpi_hw_write_port((acpi_io_address)
    342							    address +
    343							    index *
    344							    ACPI_DIV_8
    345							    (access_width),
    346							    (u32)value64,
    347							    access_width);
    348			}
    349		}
    350
    351		/*
    352		 * Index * access_width is ensured to be less than 32-bits by
    353		 * acpi_hw_validate_register().
    354		 */
    355		bit_width -=
    356		    bit_width > access_width ? access_width : bit_width;
    357		index++;
    358	}
    359
    360	ACPI_DEBUG_PRINT((ACPI_DB_IO,
    361			  "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
    362			  ACPI_FORMAT_UINT64(value), access_width,
    363			  ACPI_FORMAT_UINT64(address),
    364			  acpi_ut_get_region_name(reg->space_id)));
    365
    366	return (status);
    367}
    368
    369#if (!ACPI_REDUCED_HARDWARE)
    370/*******************************************************************************
    371 *
    372 * FUNCTION:    acpi_hw_clear_acpi_status
    373 *
    374 * PARAMETERS:  None
    375 *
    376 * RETURN:      Status
    377 *
    378 * DESCRIPTION: Clears all fixed and general purpose status bits
    379 *
    380 ******************************************************************************/
    381
    382acpi_status acpi_hw_clear_acpi_status(void)
    383{
    384	acpi_status status;
    385	acpi_cpu_flags lock_flags = 0;
    386
    387	ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
    388
    389	ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
    390			  ACPI_BITMASK_ALL_FIXED_STATUS,
    391			  ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address)));
    392
    393	lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock);
    394
    395	/* Clear the fixed events in PM1 A/B */
    396
    397	status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
    398					ACPI_BITMASK_ALL_FIXED_STATUS);
    399
    400	acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags);
    401
    402	if (ACPI_FAILURE(status)) {
    403		goto exit;
    404	}
    405
    406	/* Clear the GPE Bits in all GPE registers in all GPE blocks */
    407
    408	status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
    409
    410exit:
    411	return_ACPI_STATUS(status);
    412}
    413
    414/*******************************************************************************
    415 *
    416 * FUNCTION:    acpi_hw_get_bit_register_info
    417 *
    418 * PARAMETERS:  register_id         - Index of ACPI Register to access
    419 *
    420 * RETURN:      The bitmask to be used when accessing the register
    421 *
    422 * DESCRIPTION: Map register_id into a register bitmask.
    423 *
    424 ******************************************************************************/
    425
    426struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
    427{
    428	ACPI_FUNCTION_ENTRY();
    429
    430	if (register_id > ACPI_BITREG_MAX) {
    431		ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: 0x%X",
    432			    register_id));
    433		return (NULL);
    434	}
    435
    436	return (&acpi_gbl_bit_register_info[register_id]);
    437}
    438
    439/******************************************************************************
    440 *
    441 * FUNCTION:    acpi_hw_write_pm1_control
    442 *
    443 * PARAMETERS:  pm1a_control        - Value to be written to PM1A control
    444 *              pm1b_control        - Value to be written to PM1B control
    445 *
    446 * RETURN:      Status
    447 *
    448 * DESCRIPTION: Write the PM1 A/B control registers. These registers are
    449 *              different than the PM1 A/B status and enable registers
    450 *              in that different values can be written to the A/B registers.
    451 *              Most notably, the SLP_TYP bits can be different, as per the
    452 *              values returned from the _Sx predefined methods.
    453 *
    454 ******************************************************************************/
    455
    456acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
    457{
    458	acpi_status status;
    459
    460	ACPI_FUNCTION_TRACE(hw_write_pm1_control);
    461
    462	status =
    463	    acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block);
    464	if (ACPI_FAILURE(status)) {
    465		return_ACPI_STATUS(status);
    466	}
    467
    468	if (acpi_gbl_FADT.xpm1b_control_block.address) {
    469		status =
    470		    acpi_hw_write(pm1b_control,
    471				  &acpi_gbl_FADT.xpm1b_control_block);
    472	}
    473	return_ACPI_STATUS(status);
    474}
    475
    476/******************************************************************************
    477 *
    478 * FUNCTION:    acpi_hw_register_read
    479 *
    480 * PARAMETERS:  register_id         - ACPI Register ID
    481 *              return_value        - Where the register value is returned
    482 *
    483 * RETURN:      Status and the value read.
    484 *
    485 * DESCRIPTION: Read from the specified ACPI register
    486 *
    487 ******************************************************************************/
    488acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
    489{
    490	u32 value = 0;
    491	u64 value64;
    492	acpi_status status;
    493
    494	ACPI_FUNCTION_TRACE(hw_register_read);
    495
    496	switch (register_id) {
    497	case ACPI_REGISTER_PM1_STATUS:	/* PM1 A/B: 16-bit access each */
    498
    499		status = acpi_hw_read_multiple(&value,
    500					       &acpi_gbl_xpm1a_status,
    501					       &acpi_gbl_xpm1b_status);
    502		break;
    503
    504	case ACPI_REGISTER_PM1_ENABLE:	/* PM1 A/B: 16-bit access each */
    505
    506		status = acpi_hw_read_multiple(&value,
    507					       &acpi_gbl_xpm1a_enable,
    508					       &acpi_gbl_xpm1b_enable);
    509		break;
    510
    511	case ACPI_REGISTER_PM1_CONTROL:	/* PM1 A/B: 16-bit access each */
    512
    513		status = acpi_hw_read_multiple(&value,
    514					       &acpi_gbl_FADT.
    515					       xpm1a_control_block,
    516					       &acpi_gbl_FADT.
    517					       xpm1b_control_block);
    518
    519		/*
    520		 * Zero the write-only bits. From the ACPI specification, "Hardware
    521		 * Write-Only Bits": "Upon reads to registers with write-only bits,
    522		 * software masks out all write-only bits."
    523		 */
    524		value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
    525		break;
    526
    527	case ACPI_REGISTER_PM2_CONTROL:	/* 8-bit access */
    528
    529		status =
    530		    acpi_hw_read(&value64, &acpi_gbl_FADT.xpm2_control_block);
    531		if (ACPI_SUCCESS(status)) {
    532			value = (u32)value64;
    533		}
    534		break;
    535
    536	case ACPI_REGISTER_PM_TIMER:	/* 32-bit access */
    537
    538		status = acpi_hw_read(&value64, &acpi_gbl_FADT.xpm_timer_block);
    539		if (ACPI_SUCCESS(status)) {
    540			value = (u32)value64;
    541		}
    542
    543		break;
    544
    545	case ACPI_REGISTER_SMI_COMMAND_BLOCK:	/* 8-bit access */
    546
    547		status =
    548		    acpi_hw_read_port(acpi_gbl_FADT.smi_command, &value, 8);
    549		break;
    550
    551	default:
    552
    553		ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
    554		status = AE_BAD_PARAMETER;
    555		break;
    556	}
    557
    558	if (ACPI_SUCCESS(status)) {
    559		*return_value = (u32)value;
    560	}
    561
    562	return_ACPI_STATUS(status);
    563}
    564
    565/******************************************************************************
    566 *
    567 * FUNCTION:    acpi_hw_register_write
    568 *
    569 * PARAMETERS:  register_id         - ACPI Register ID
    570 *              value               - The value to write
    571 *
    572 * RETURN:      Status
    573 *
    574 * DESCRIPTION: Write to the specified ACPI register
    575 *
    576 * NOTE: In accordance with the ACPI specification, this function automatically
    577 * preserves the value of the following bits, meaning that these bits cannot be
    578 * changed via this interface:
    579 *
    580 * PM1_CONTROL[0] = SCI_EN
    581 * PM1_CONTROL[9]
    582 * PM1_STATUS[11]
    583 *
    584 * ACPI References:
    585 * 1) Hardware Ignored Bits: When software writes to a register with ignored
    586 *      bit fields, it preserves the ignored bit fields
    587 * 2) SCI_EN: OSPM always preserves this bit position
    588 *
    589 ******************************************************************************/
    590
    591acpi_status acpi_hw_register_write(u32 register_id, u32 value)
    592{
    593	acpi_status status;
    594	u32 read_value;
    595	u64 read_value64;
    596
    597	ACPI_FUNCTION_TRACE(hw_register_write);
    598
    599	switch (register_id) {
    600	case ACPI_REGISTER_PM1_STATUS:	/* PM1 A/B: 16-bit access each */
    601		/*
    602		 * Handle the "ignored" bit in PM1 Status. According to the ACPI
    603		 * specification, ignored bits are to be preserved when writing.
    604		 * Normally, this would mean a read/modify/write sequence. However,
    605		 * preserving a bit in the status register is different. Writing a
    606		 * one clears the status, and writing a zero preserves the status.
    607		 * Therefore, we must always write zero to the ignored bit.
    608		 *
    609		 * This behavior is clarified in the ACPI 4.0 specification.
    610		 */
    611		value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
    612
    613		status = acpi_hw_write_multiple(value,
    614						&acpi_gbl_xpm1a_status,
    615						&acpi_gbl_xpm1b_status);
    616		break;
    617
    618	case ACPI_REGISTER_PM1_ENABLE:	/* PM1 A/B: 16-bit access each */
    619
    620		status = acpi_hw_write_multiple(value,
    621						&acpi_gbl_xpm1a_enable,
    622						&acpi_gbl_xpm1b_enable);
    623		break;
    624
    625	case ACPI_REGISTER_PM1_CONTROL:	/* PM1 A/B: 16-bit access each */
    626		/*
    627		 * Perform a read first to preserve certain bits (per ACPI spec)
    628		 * Note: This includes SCI_EN, we never want to change this bit
    629		 */
    630		status = acpi_hw_read_multiple(&read_value,
    631					       &acpi_gbl_FADT.
    632					       xpm1a_control_block,
    633					       &acpi_gbl_FADT.
    634					       xpm1b_control_block);
    635		if (ACPI_FAILURE(status)) {
    636			goto exit;
    637		}
    638
    639		/* Insert the bits to be preserved */
    640
    641		ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
    642				 read_value);
    643
    644		/* Now we can write the data */
    645
    646		status = acpi_hw_write_multiple(value,
    647						&acpi_gbl_FADT.
    648						xpm1a_control_block,
    649						&acpi_gbl_FADT.
    650						xpm1b_control_block);
    651		break;
    652
    653	case ACPI_REGISTER_PM2_CONTROL:	/* 8-bit access */
    654		/*
    655		 * For control registers, all reserved bits must be preserved,
    656		 * as per the ACPI spec.
    657		 */
    658		status =
    659		    acpi_hw_read(&read_value64,
    660				 &acpi_gbl_FADT.xpm2_control_block);
    661		if (ACPI_FAILURE(status)) {
    662			goto exit;
    663		}
    664		read_value = (u32)read_value64;
    665
    666		/* Insert the bits to be preserved */
    667
    668		ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS,
    669				 read_value);
    670
    671		status =
    672		    acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block);
    673		break;
    674
    675	case ACPI_REGISTER_PM_TIMER:	/* 32-bit access */
    676
    677		status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block);
    678		break;
    679
    680	case ACPI_REGISTER_SMI_COMMAND_BLOCK:	/* 8-bit access */
    681
    682		/* SMI_CMD is currently always in IO space */
    683
    684		status =
    685		    acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8);
    686		break;
    687
    688	default:
    689
    690		ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
    691		status = AE_BAD_PARAMETER;
    692		break;
    693	}
    694
    695exit:
    696	return_ACPI_STATUS(status);
    697}
    698
    699/******************************************************************************
    700 *
    701 * FUNCTION:    acpi_hw_read_multiple
    702 *
    703 * PARAMETERS:  value               - Where the register value is returned
    704 *              register_a           - First ACPI register (required)
    705 *              register_b           - Second ACPI register (optional)
    706 *
    707 * RETURN:      Status
    708 *
    709 * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
    710 *
    711 ******************************************************************************/
    712
    713static acpi_status
    714acpi_hw_read_multiple(u32 *value,
    715		      struct acpi_generic_address *register_a,
    716		      struct acpi_generic_address *register_b)
    717{
    718	u32 value_a = 0;
    719	u32 value_b = 0;
    720	u64 value64;
    721	acpi_status status;
    722
    723	/* The first register is always required */
    724
    725	status = acpi_hw_read(&value64, register_a);
    726	if (ACPI_FAILURE(status)) {
    727		return (status);
    728	}
    729	value_a = (u32)value64;
    730
    731	/* Second register is optional */
    732
    733	if (register_b->address) {
    734		status = acpi_hw_read(&value64, register_b);
    735		if (ACPI_FAILURE(status)) {
    736			return (status);
    737		}
    738		value_b = (u32)value64;
    739	}
    740
    741	/*
    742	 * OR the two return values together. No shifting or masking is necessary,
    743	 * because of how the PM1 registers are defined in the ACPI specification:
    744	 *
    745	 * "Although the bits can be split between the two register blocks (each
    746	 * register block has a unique pointer within the FADT), the bit positions
    747	 * are maintained. The register block with unimplemented bits (that is,
    748	 * those implemented in the other register block) always returns zeros,
    749	 * and writes have no side effects"
    750	 */
    751	*value = (value_a | value_b);
    752	return (AE_OK);
    753}
    754
    755/******************************************************************************
    756 *
    757 * FUNCTION:    acpi_hw_write_multiple
    758 *
    759 * PARAMETERS:  value               - The value to write
    760 *              register_a           - First ACPI register (required)
    761 *              register_b           - Second ACPI register (optional)
    762 *
    763 * RETURN:      Status
    764 *
    765 * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
    766 *
    767 ******************************************************************************/
    768
    769static acpi_status
    770acpi_hw_write_multiple(u32 value,
    771		       struct acpi_generic_address *register_a,
    772		       struct acpi_generic_address *register_b)
    773{
    774	acpi_status status;
    775
    776	/* The first register is always required */
    777
    778	status = acpi_hw_write(value, register_a);
    779	if (ACPI_FAILURE(status)) {
    780		return (status);
    781	}
    782
    783	/*
    784	 * Second register is optional
    785	 *
    786	 * No bit shifting or clearing is necessary, because of how the PM1
    787	 * registers are defined in the ACPI specification:
    788	 *
    789	 * "Although the bits can be split between the two register blocks (each
    790	 * register block has a unique pointer within the FADT), the bit positions
    791	 * are maintained. The register block with unimplemented bits (that is,
    792	 * those implemented in the other register block) always returns zeros,
    793	 * and writes have no side effects"
    794	 */
    795	if (register_b->address) {
    796		status = acpi_hw_write(value, register_b);
    797	}
    798
    799	return (status);
    800}
    801
    802#endif				/* !ACPI_REDUCED_HARDWARE */