From 84b43284af40742abeb2cdd6998a4084866ba015 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 4 Sep 2020 18:27:27 +0200 Subject: [PATCH 1/6] ACPICA: Validate GPE blocks at init time Some of the checks done by acpi_hw_read() and acpi_hw_write(), which are used for accessing GPE registers, are redundant in the specific case of GPE registers and the ones that are not redundant can be done upfront at the initialization time so as to fail the initialization if they are not passed instead of failing every access to the affected GPE registers going forward (including accesses from the SCI interrupt handler). Modify the GPE blocks initialization code accordingly. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/achware.h | 2 ++ drivers/acpi/acpica/evgpeblk.c | 17 +++++++++++++++++ drivers/acpi/acpica/hwvalid.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index ebf6453d0e21..f1f644b58b15 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -73,6 +73,8 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width); acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width); +acpi_status acpi_hw_validate_io_block(u64 address, u32 bit_width, u32 count); + /* * hwgpe - GPE support */ diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 132adff1e131..eb5d98757fdc 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -317,6 +317,23 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, return_ACPI_STATUS(AE_OK); } + /* Validate the space_ID */ + + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + ACPI_ERROR((AE_INFO, + "Unsupported address space: 0x%X", space_id)); + return_ACPI_STATUS(AE_SUPPORT); + } + + if (space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + status = acpi_hw_validate_io_block(address, + ACPI_GPE_REGISTER_WIDTH, + register_count); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(status); + } + /* Allocate a new GPE block */ gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info)); diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 4d94861e6093..b2ca7dfd3fc9 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -292,3 +292,33 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) return (AE_OK); } + +/****************************************************************************** + * + * FUNCTION: acpi_hw_validate_io_block + * + * PARAMETERS: Address Address of I/O port/register blobk + * bit_width Number of bits (8,16,32) in each register + * count Number of registers in the block + * + * RETURN: Status + * + * DESCRIPTION: Validates a block of I/O ports/registers. + * + ******************************************************************************/ + +acpi_status acpi_hw_validate_io_block(u64 address, u32 bit_width, u32 count) +{ + acpi_status status; + + while (count--) { + status = acpi_hw_validate_io_request((acpi_io_address)address, + bit_width); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(status); + + address += ACPI_DIV_8(bit_width); + } + + return_ACPI_STATUS(AE_OK); +} From f06011ad6225b0f5e4246b5635c5570fa8d5fcdf Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 4 Sep 2020 18:27:43 +0200 Subject: [PATCH 2/6] ACPICA: Introduce acpi_hw_gpe_read() and acpi_hw_gpe_write() Now that GPE blocks are validated at the initialization time, accesses to GPE registers can be made more straightforward by ommitting all of the redundant checks in acpi_hw_read() and acpi_hw_write() and only invoking the OS-provided helper for the given type of access (read or write) and the address space holding these registers. For this reason, introduce simplified routines for accessing GPE registers, acpi_hw_gpe_read() and acpi_hw_gpe_write(), designed in accordance with the above observation, and modify all of the code accessing GPE registers to use them instead of acpi_hw_read() and acpi_hw_write(), respectively. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/achware.h | 4 ++ drivers/acpi/acpica/evgpe.c | 4 +- drivers/acpi/acpica/evgpeblk.c | 4 +- drivers/acpi/acpica/hwgpe.c | 92 ++++++++++++++++++++++++++++------ 4 files changed, 84 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index f1f644b58b15..4dba7229f9c1 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -78,6 +78,10 @@ acpi_status acpi_hw_validate_io_block(u64 address, u32 bit_width, u32 count); /* * hwgpe - GPE support */ +acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_generic_address *reg); + +acpi_status acpi_hw_gpe_write(u64 value, struct acpi_generic_address *reg); + u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info); acpi_status diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 3e39907fedd9..06b9c8dd11c9 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -656,14 +656,14 @@ acpi_ev_detect_gpe(struct acpi_namespace_node *gpe_device, /* GPE currently enabled (enable bit == 1)? */ - status = acpi_hw_read(&enable_reg, &gpe_register_info->enable_address); + status = acpi_hw_gpe_read(&enable_reg, &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { goto error_exit; } /* GPE currently active (status bit == 1)? */ - status = acpi_hw_read(&status_reg, &gpe_register_info->status_address); + status = acpi_hw_gpe_read(&status_reg, &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { goto error_exit; } diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index eb5d98757fdc..150c916dca5e 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -251,14 +251,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* Disable all GPEs within this register */ - status = acpi_hw_write(0x00, &this_register->enable_address); + status = acpi_hw_gpe_write(0x00, &this_register->enable_address); if (ACPI_FAILURE(status)) { goto error_exit; } /* Clear any pending GPE events within this register */ - status = acpi_hw_write(0xFF, &this_register->status_address); + status = acpi_hw_gpe_write(0xFF, &this_register->status_address); if (ACPI_FAILURE(status)) { goto error_exit; } diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 49c46d4dd070..6cc88524839d 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -24,6 +24,66 @@ static acpi_status acpi_hw_gpe_enable_write(u8 enable_mask, struct acpi_gpe_register_info *gpe_register_info); +/****************************************************************************** + * + * FUNCTION: acpi_hw_gpe_read + * + * PARAMETERS: value - Where the value is returned + * reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Read from a GPE register in either memory or IO space. + * + * LIMITATIONS: + * space_ID must be system_memory or system_IO. + * + ******************************************************************************/ + +acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_generic_address *reg) +{ + acpi_status status; + u32 value32; + + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + return acpi_os_read_memory((acpi_physical_address)reg->address, + value, ACPI_GPE_REGISTER_WIDTH); + } + + status = acpi_os_read_port((acpi_io_address)reg->address, + &value32, ACPI_GPE_REGISTER_WIDTH); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(status); + + *value = (u64)value32; + + return_ACPI_STATUS(AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_hw_gpe_write + * + * PARAMETERS: value - Value to be written + * reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Write to a GPE register in either memory or IO space. + * + ******************************************************************************/ + +acpi_status acpi_hw_gpe_write(u64 value, struct acpi_generic_address *reg) +{ + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + return acpi_os_write_memory((acpi_physical_address)reg->address, + value, ACPI_GPE_REGISTER_WIDTH); + } + + return acpi_os_write_port((acpi_io_address)reg->address, (u32)value, + ACPI_GPE_REGISTER_WIDTH); +} + /****************************************************************************** * * FUNCTION: acpi_hw_get_gpe_register_bit @@ -79,7 +139,8 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) /* Get current value of the enable register that contains this GPE */ - status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address); + status = acpi_hw_gpe_read(&enable_mask, + &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -118,9 +179,8 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) /* Write the updated enable mask */ - status = - acpi_hw_write(enable_mask, - &gpe_register_info->enable_address); + status = acpi_hw_gpe_write(enable_mask, + &gpe_register_info->enable_address); } return (status); } @@ -158,8 +218,8 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info *gpe_event_info) */ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); - status = - acpi_hw_write(register_bit, &gpe_register_info->status_address); + status = acpi_hw_gpe_write(register_bit, + &gpe_register_info->status_address); return (status); } @@ -227,7 +287,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, /* GPE currently enabled (enable bit == 1)? */ - status = acpi_hw_read(&in_byte, &gpe_register_info->enable_address); + status = acpi_hw_gpe_read(&in_byte, &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -238,7 +298,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, /* GPE currently active (status bit == 1)? */ - status = acpi_hw_read(&in_byte, &gpe_register_info->status_address); + status = acpi_hw_gpe_read(&in_byte, &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { return (status); } @@ -274,7 +334,8 @@ acpi_hw_gpe_enable_write(u8 enable_mask, gpe_register_info->enable_mask = enable_mask; - status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); + status = acpi_hw_gpe_write(enable_mask, + &gpe_register_info->enable_address); return (status); } @@ -341,9 +402,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* Clear status on all GPEs in this register */ - status = - acpi_hw_write(0xFF, - &gpe_block->register_info[i].status_address); + status = acpi_hw_gpe_write(0xFF, + &gpe_block->register_info[i].status_address); if (ACPI_FAILURE(status)) { return (status); } @@ -481,14 +541,14 @@ acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info, for (i = 0; i < gpe_block->register_count; i++) { gpe_register_info = &gpe_block->register_info[i]; - status = acpi_hw_read(&in_enable, - &gpe_register_info->enable_address); + status = acpi_hw_gpe_read(&in_enable, + &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { continue; } - status = acpi_hw_read(&in_status, - &gpe_register_info->status_address); + status = acpi_hw_gpe_read(&in_status, + &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { continue; } From 9da8e9ac171438525e4c1c377609818ef1a6237b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 4 Sep 2020 18:27:52 +0200 Subject: [PATCH 3/6] ACPICA: Introduce special struct type for GPE register addresses Notice that the bit_width, bit_offset and access_width fields in struct acpi_generic_address are not used during GPE register accesses any more, so introduce a simplified address structure type, struct acpi_gpe_address, to represent addresses of GPE registers and use it instead of struct acpi_generic_address in struct acpi_gpe_register_info. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/achware.h | 4 ++-- drivers/acpi/acpica/aclocal.h | 11 +++++++++-- drivers/acpi/acpica/evgpeblk.c | 6 ------ drivers/acpi/acpica/hwgpe.c | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 4dba7229f9c1..6ab92e28330d 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -78,9 +78,9 @@ acpi_status acpi_hw_validate_io_block(u64 address, u32 bit_width, u32 count); /* * hwgpe - GPE support */ -acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_generic_address *reg); +acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg); -acpi_status acpi_hw_gpe_write(u64 value, struct acpi_generic_address *reg); +acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg); u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index af58cd2dc9d3..f83b98fa13ac 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -454,11 +454,18 @@ struct acpi_gpe_event_info { u8 disable_for_dispatch; /* Masked during dispatching */ }; +/* GPE register address */ + +struct acpi_gpe_address { + u8 space_id; /* Address space where the register exists */ + u64 address; /* 64-bit address of the register */ +}; + /* Information about a GPE register pair, one per each status/enable pair in an array */ struct acpi_gpe_register_info { - struct acpi_generic_address status_address; /* Address of status reg */ - struct acpi_generic_address enable_address; /* Address of enable reg */ + struct acpi_gpe_address status_address; /* Address of status reg */ + struct acpi_gpe_address enable_address; /* Address of enable reg */ u16 base_gpe_number; /* Base GPE number for this register */ u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ u8 enable_for_run; /* GPEs to keep enabled when running */ diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 150c916dca5e..f5298be4273a 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -233,12 +233,6 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) this_register->status_address.space_id = gpe_block->space_id; this_register->enable_address.space_id = gpe_block->space_id; - this_register->status_address.bit_width = - ACPI_GPE_REGISTER_WIDTH; - this_register->enable_address.bit_width = - ACPI_GPE_REGISTER_WIDTH; - this_register->status_address.bit_offset = 0; - this_register->enable_address.bit_offset = 0; /* Init the event_info for each GPE within this register */ diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 6cc88524839d..a0e71f34c77a 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -29,7 +29,7 @@ acpi_hw_gpe_enable_write(u8 enable_mask, * FUNCTION: acpi_hw_gpe_read * * PARAMETERS: value - Where the value is returned - * reg - GAS register structure + * reg - GPE register structure * * RETURN: Status * @@ -40,7 +40,7 @@ acpi_hw_gpe_enable_write(u8 enable_mask, * ******************************************************************************/ -acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_generic_address *reg) +acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg) { acpi_status status; u32 value32; @@ -65,7 +65,7 @@ acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_generic_address *reg) * FUNCTION: acpi_hw_gpe_write * * PARAMETERS: value - Value to be written - * reg - GAS register structure + * reg - GPE register structure * * RETURN: Status * @@ -73,7 +73,7 @@ acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_generic_address *reg) * ******************************************************************************/ -acpi_status acpi_hw_gpe_write(u64 value, struct acpi_generic_address *reg) +acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg) { if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { return acpi_os_write_memory((acpi_physical_address)reg->address, From 7a8379eb41a47d37e93d34f09ca1c3b7d10de073 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Sep 2020 16:44:45 +0200 Subject: [PATCH 4/6] ACPICA: Add support for using logical addresses of GPE blocks The logical address of every GPE block in system memory must be known before passing it to acpi_ev_initialize_gpe_block(), because memory cannot be mapped on the fly from an interrupt handler. Accordingly, the host OS must map every GPE block in system memory upfront and it can store the logical addresses of GPE blocks for future use. If these logical addresses were known to ACPICA, it could use them instead of the corresponding physical addresses of GPE block for GPE register accesses and the memory mapping lookups carried out by acpi_os_read_memory() and acpi_os_write_memory() on every attempt to access a GPE register would not be necessary any more. To allow that to happen, introduce the ACPI_GPE_USE_LOGICAL_ADDRESSES symbol to indicate whether or not the host OS wants ACPICA to use the logical addresses of GPE registers in system memory directly (which is the case if this symbol is defined). Moreover, conditional on whether ACPI_GPE_USE_LOGICAL_ADDRESSES is defined, introduce two new global variables for storing the logical addresses of the FADT GPE blocks 0 and 1, respectively, acpi_gbl_xgpe0_block_logical_address and acpi_gbl_xgpe1_block_logical_address, make acpi_ev_gpe_initialize() pass their values instead of the physical addresses of the GPE blocks in question to acpi_ev_create_gpe_block() and modify acpi_hw_gpe_read() and acpi_hw_gpe_write() to access memory directly via the addresses stored in the struct acpi_gpe_address objects, which are expected to be the logical addresses of GPE registers if ACPI_GPE_USE_LOGICAL_ADDRESSES is defined. With the above changes in place, a host OS wanting ACPICA to access GPE registers directly through their logical addresses needs to define the ACPI_GPE_USE_LOGICAL_ADDRESSES symbol and make sure that the logical addresses of the FADT GPE blocks 0 and 1 are stored in acpi_gbl_xgpe0_block_logical_address and acpi_gbl_xgpe1_block_logical_address, respectively, prior to calling acpi_ev_gpe_initialize(). [If such a host OS also uses acpi_install_gpe_block() to add non-FADT GPE register blocks located in system memory, it must pass their logical addresses instead of their physical addresses to this function.] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 6 ++++++ drivers/acpi/acpica/evgpeinit.c | 23 +++++++++++++++++------ drivers/acpi/acpica/hwgpe.c | 10 ++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 1030a0ce1599..2fee91f57b21 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -42,6 +42,12 @@ ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_enable); ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_status); ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_enable); +#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES +ACPI_GLOBAL(unsigned long, acpi_gbl_xgpe0_block_logical_address); +ACPI_GLOBAL(unsigned long, acpi_gbl_xgpe1_block_logical_address); + +#endif /* ACPI_GPE_USE_LOGICAL_ADDRESSES */ + /* * Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is * determined by the revision of the DSDT: If the DSDT revision is less than diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 6effd8076dcc..6d82d30d8f7b 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -32,6 +32,16 @@ ACPI_MODULE_NAME("evgpeinit") * kernel boot time as well. */ +#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES +#define ACPI_FADT_GPE_BLOCK_ADDRESS(N) \ + acpi_gbl_FADT.xgpe##N##_block.space_id == \ + ACPI_ADR_SPACE_SYSTEM_MEMORY ? \ + (u64)acpi_gbl_xgpe##N##_block_logical_address : \ + acpi_gbl_FADT.xgpe##N##_block.address +#else +#define ACPI_FADT_GPE_BLOCK_ADDRESS(N) acpi_gbl_FADT.xgpe##N##_block.address +#endif /* ACPI_GPE_USE_LOGICAL_ADDRESSES */ + /******************************************************************************* * * FUNCTION: acpi_ev_gpe_initialize @@ -49,6 +59,7 @@ acpi_status acpi_ev_gpe_initialize(void) u32 register_count1 = 0; u32 gpe_number_max = 0; acpi_status status; + u64 address; ACPI_FUNCTION_TRACE(ev_gpe_initialize); @@ -85,8 +96,9 @@ acpi_status acpi_ev_gpe_initialize(void) * If EITHER the register length OR the block address are zero, then that * particular block is not supported. */ - if (acpi_gbl_FADT.gpe0_block_length && - acpi_gbl_FADT.xgpe0_block.address) { + address = ACPI_FADT_GPE_BLOCK_ADDRESS(0); + + if (acpi_gbl_FADT.gpe0_block_length && address) { /* GPE block 0 exists (has both length and address > 0) */ @@ -97,7 +109,6 @@ acpi_status acpi_ev_gpe_initialize(void) /* Install GPE Block 0 */ status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - acpi_gbl_FADT.xgpe0_block. address, acpi_gbl_FADT.xgpe0_block. space_id, register_count0, 0, @@ -110,8 +121,9 @@ acpi_status acpi_ev_gpe_initialize(void) } } - if (acpi_gbl_FADT.gpe1_block_length && - acpi_gbl_FADT.xgpe1_block.address) { + address = ACPI_FADT_GPE_BLOCK_ADDRESS(1); + + if (acpi_gbl_FADT.gpe1_block_length && address) { /* GPE block 1 exists (has both length and address > 0) */ @@ -137,7 +149,6 @@ acpi_status acpi_ev_gpe_initialize(void) status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - acpi_gbl_FADT.xgpe1_block. address, acpi_gbl_FADT.xgpe1_block. space_id, register_count1, diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index a0e71f34c77a..37bb67ef3232 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -46,8 +46,13 @@ acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg) u32 value32; if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { +#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES + *value = (u64)ACPI_GET8(reg->address); + return_ACPI_STATUS(AE_OK); +#else return acpi_os_read_memory((acpi_physical_address)reg->address, value, ACPI_GPE_REGISTER_WIDTH); +#endif } status = acpi_os_read_port((acpi_io_address)reg->address, @@ -76,8 +81,13 @@ acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg) acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg) { if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { +#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES + ACPI_SET8(reg->address, value); + return_ACPI_STATUS(AE_OK); +#else return acpi_os_write_memory((acpi_physical_address)reg->address, value, ACPI_GPE_REGISTER_WIDTH); +#endif } return acpi_os_write_port((acpi_io_address)reg->address, (u32)value, From 6915564dc5a8ab831a016e0cd0a8a3c68230287b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Sep 2020 14:59:35 +0200 Subject: [PATCH 5/6] ACPI: OSL: Change the type of acpi_os_map_generic_address() return value Modify acpi_os_map_generic_address() to return the pointer returned by acpi_os_map_iomem() which represents the logical address corresponding to the struct acpi_generic_address argument passed to it or NULL if that address cannot be obtained (for example, the argument does not represent an address in system memory or it could not be mapped by the OS). Among other things, that will allow the ACPI OS layer to pass the logical addresses of the FADT GPE blocks 0 and 1 to ACPICA going forward. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/apei-base.c | 6 +++++- drivers/acpi/osl.c | 18 +++++++----------- include/acpi/acpi_io.h | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index e358d0046494..552fd9ffaca4 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -632,7 +632,11 @@ int apei_map_generic_address(struct acpi_generic_address *reg) rc = apei_check_gar(reg, &address, &access_bit_width); if (rc) return rc; - return acpi_os_map_generic_address(reg); + + if (!acpi_os_map_generic_address(reg)) + return -ENXIO; + + return 0; } EXPORT_SYMBOL_GPL(apei_map_generic_address); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 4a0b07792233..3a50d8fa310b 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -447,24 +447,19 @@ void __ref acpi_os_unmap_memory(void *virt, acpi_size size) } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); -int acpi_os_map_generic_address(struct acpi_generic_address *gas) +void __iomem *acpi_os_map_generic_address(struct acpi_generic_address *gas) { u64 addr; - void __iomem *virt; if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) - return 0; + return NULL; /* Handle possible alignment issues */ memcpy(&addr, &gas->address, sizeof(addr)); if (!addr || !gas->bit_width) - return -EINVAL; + return NULL; - virt = acpi_os_map_iomem(addr, gas->bit_width / 8); - if (!virt) - return -EIO; - - return 0; + return acpi_os_map_iomem(addr, gas->bit_width / 8); } EXPORT_SYMBOL(acpi_os_map_generic_address); @@ -1756,10 +1751,11 @@ acpi_status __init acpi_os_initialize(void) * Use acpi_os_map_generic_address to pre-map the reset * register if it's in system memory. */ - int rv; + void *rv; rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register); - pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv); + pr_debug(PREFIX "%s: map reset_reg %s\n", __func__, + rv ? "successful" : "failed"); } acpi_os_initialized = true; diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h index 12d8bd333fe7..027faa8883aa 100644 --- a/include/acpi/acpi_io.h +++ b/include/acpi/acpi_io.h @@ -21,7 +21,7 @@ void __iomem __ref void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size); void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); -int acpi_os_map_generic_address(struct acpi_generic_address *addr); +void __iomem *acpi_os_map_generic_address(struct acpi_generic_address *addr); void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); #endif From 85f94020033f931a5918ab26281b2afbe4d68b73 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Sep 2020 14:59:42 +0200 Subject: [PATCH 6/6] ACPI: OSL: Make ACPICA use logical addresses of GPE blocks Define ACPI_GPE_USE_LOGICAL_ADDRESSES in aclinux.h and modify acpi_os_initialize() to store the logical addresses of the FADT GPE blocks 0 and 1 in acpi_gbl_xgpe0_block_logical_address and acpi_gbl_xgpe1_block_logical_address, respectively, so as to allow ACPICA to use them for accessing GPE registers in system memory, instead of using their physical addresses and looking up the corresponding logical addresses on every access attempt, which is inefficient. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 12 ++++++++++-- include/acpi/platform/aclinux.h | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 3a50d8fa310b..0418febc5cf2 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1744,8 +1744,12 @@ acpi_status __init acpi_os_initialize(void) { acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block); acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block); - acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); - acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); + + acpi_gbl_xgpe0_block_logical_address = + (unsigned long)acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); + acpi_gbl_xgpe1_block_logical_address = + (unsigned long)acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); + if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) { /* * Use acpi_os_map_generic_address to pre-map the reset @@ -1783,8 +1787,12 @@ acpi_status acpi_os_terminate(void) acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block); acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block); + acpi_gbl_xgpe0_block_logical_address = 0UL; + acpi_gbl_xgpe1_block_logical_address = 0UL; + acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block); acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block); + if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) acpi_os_unmap_generic_address(&acpi_gbl_FADT.reset_register); diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 987e2af7c335..4151c76141fa 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -118,6 +118,10 @@ #define USE_NATIVE_ALLOCATE_ZEROED +/* Use logical addresses for accessing GPE registers in system memory */ + +#define ACPI_GPE_USE_LOGICAL_ADDRESSES + /* * Overrides for in-kernel ACPICA */