diff options
Diffstat (limited to 'drivers/acpi')
44 files changed, 629 insertions, 238 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index cdbdf68bd98f..60b5424bd318 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -524,6 +524,23 @@ config ACPI_PPTT bool endif +config ACPI_PCC + bool "ACPI PCC Address Space" + depends on PCC + default y + help + The PCC Address Space also referred as PCC Operation Region pertains + to the region of PCC subspace that succeeds the PCC signature. + + The PCC Operation Region works in conjunction with the PCC Table + (Platform Communications Channel Table). PCC subspaces that are + marked for use as PCC Operation Regions must not be used as PCC + subspaces for the standard ACPI features such as CPPC, RASF, PDTT and + MPST. These standard features must always use the PCC Table instead. + + Enable this feature if you want to set up and install the PCC Address + Space handler to handle PCC OpRegion in the firmware. + source "drivers/acpi/pmic/Kconfig" config ACPI_VIOT diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 3018714e87d9..08c2d985c57c 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -67,6 +67,7 @@ acpi-$(CONFIG_ACPI_LPIT) += acpi_lpit.o acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o acpi-$(CONFIG_ACPI_PRMT) += prmt.o +acpi-$(CONFIG_ACPI_PCC) += acpi_pcc.o # Address translation acpi-$(CONFIG_ACPI_ADXL) += acpi_adxl.o diff --git a/drivers/acpi/acpi_pcc.c b/drivers/acpi/acpi_pcc.c new file mode 100644 index 000000000000..41e3ebd204ff --- /dev/null +++ b/drivers/acpi/acpi_pcc.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Author: Sudeep Holla <sudeep.holla@arm.com> + * Copyright 2021 Arm Limited + * + * The PCC Address Space also referred as PCC Operation Region pertains to the + * region of PCC subspace that succeeds the PCC signature. The PCC Operation + * Region works in conjunction with the PCC Table(Platform Communications + * Channel Table). PCC subspaces that are marked for use as PCC Operation + * Regions must not be used as PCC subspaces for the standard ACPI features + * such as CPPC, RASF, PDTT and MPST. These standard features must always use + * the PCC Table instead. + * + * This driver sets up the PCC Address Space and installs an handler to enable + * handling of PCC OpRegion in the firmware. + * + */ +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/completion.h> +#include <linux/idr.h> +#include <linux/io.h> + +#include <acpi/pcc.h> + +struct pcc_data { + struct pcc_mbox_chan *pcc_chan; + void __iomem *pcc_comm_addr; + struct completion done; + struct mbox_client cl; + struct acpi_pcc_info ctx; +}; + +struct acpi_pcc_info pcc_ctx; + +static void pcc_rx_callback(struct mbox_client *cl, void *m) +{ + struct pcc_data *data = container_of(cl, struct pcc_data, cl); + + complete(&data->done); +} + +static acpi_status +acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function, + void *handler_context, void **region_context) +{ + struct pcc_data *data; + struct acpi_pcc_info *ctx = handler_context; + struct pcc_mbox_chan *pcc_chan; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return AE_NO_MEMORY; + + data->cl.rx_callback = pcc_rx_callback; + data->cl.knows_txdone = true; + data->ctx.length = ctx->length; + data->ctx.subspace_id = ctx->subspace_id; + data->ctx.internal_buffer = ctx->internal_buffer; + + init_completion(&data->done); + data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id); + if (IS_ERR(data->pcc_chan)) { + pr_err("Failed to find PCC channel for subspace %d\n", + ctx->subspace_id); + return AE_NOT_FOUND; + } + + pcc_chan = data->pcc_chan; + data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr, + pcc_chan->shmem_size); + if (!data->pcc_comm_addr) { + pr_err("Failed to ioremap PCC comm region mem for %d\n", + ctx->subspace_id); + return AE_NO_MEMORY; + } + + *region_context = data; + return AE_OK; +} + +static acpi_status +acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr, + u32 bits, acpi_integer *value, + void *handler_context, void *region_context) +{ + int ret; + struct pcc_data *data = region_context; + + reinit_completion(&data->done); + + /* Write to Shared Memory */ + memcpy_toio(data->pcc_comm_addr, (void *)value, data->ctx.length); + + ret = mbox_send_message(data->pcc_chan->mchan, NULL); + if (ret < 0) + return AE_ERROR; + + if (data->pcc_chan->mchan->mbox->txdone_irq) + wait_for_completion(&data->done); + + mbox_client_txdone(data->pcc_chan->mchan, ret); + + memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length); + + return AE_OK; +} + +void __init acpi_init_pcc(void) +{ + acpi_status status; + + status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, + ACPI_ADR_SPACE_PLATFORM_COMM, + &acpi_pcc_address_space_handler, + &acpi_pcc_address_space_setup, + &pcc_ctx); + if (ACPI_FAILURE(status)) + pr_alert("OperationRegion handler could not be installed\n"); +} diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 82a75964343b..b29ba436944a 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -224,6 +224,11 @@ acpi_ev_pci_bar_region_setup(acpi_handle handle, void *handler_context, void **region_context); acpi_status +acpi_ev_data_table_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context); + +acpi_status acpi_ev_default_region_setup(acpi_handle handle, u32 function, void *handler_context, void **region_context); diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 9db5ae0f79ea..0aa0d847cb25 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -138,6 +138,7 @@ struct acpi_object_region { union acpi_operand_object *next; acpi_physical_address address; u32 length; + void *pointer; /* Only for data table regions */ }; struct acpi_object_method { diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index e2d0046799a2..533802fe73e9 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -35,7 +35,8 @@ acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, acpi_status acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, - acpi_physical_address address, u8 flags); + acpi_physical_address address, + u8 flags, struct acpi_table_header *table); void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); @@ -86,6 +87,7 @@ acpi_tb_release_table(struct acpi_table_header *table, acpi_status acpi_tb_install_standard_table(acpi_physical_address address, u8 flags, + struct acpi_table_header *table, u8 reload, u8 override, u32 *table_index); void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc); @@ -95,7 +97,9 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node); acpi_status acpi_tb_install_and_load_table(acpi_physical_address address, - u8 flags, u8 override, u32 *table_index); + u8 flags, + struct acpi_table_header *table, + u8 override, u32 *table_index); acpi_status acpi_tb_unload_table(u32 table_index); diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 639635291ab7..44c448269861 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -531,6 +531,7 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table); obj_desc->region.length = table->length; + obj_desc->region.pointer = table; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", obj_desc, diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index c0cd7147a5a3..8f43d38dc4ca 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -386,7 +386,7 @@ acpi_ev_install_space_handler(struct acpi_namespace_node *node, case ACPI_ADR_SPACE_DATA_TABLE: handler = acpi_ex_data_table_space_handler; - setup = NULL; + setup = acpi_ev_data_table_region_setup; break; default: diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 4ef43c8ef5e7..b9d77d327d38 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -162,6 +162,16 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, return_ACPI_STATUS(AE_NOT_EXIST); } + if (region_obj->region.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { + struct acpi_pcc_info *ctx = + handler_desc->address_space.context; + + ctx->internal_buffer = + field_obj->field.internal_pcc_buffer; + ctx->length = (u16)region_obj->region.length; + ctx->subspace_id = (u8)region_obj->region.address; + } + /* * We must exit the interpreter because the region setup will * potentially execute control methods (for example, the _REG method diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 984c172453bf..d28dee929e61 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -408,6 +408,58 @@ acpi_ev_cmos_region_setup(acpi_handle handle, /******************************************************************************* * + * FUNCTION: acpi_ev_data_table_region_setup + * + * PARAMETERS: handle - Region we are interested in + * function - Start or stop + * handler_context - Address space handler context + * region_context - Region specific context + * + * RETURN: Status + * + * DESCRIPTION: Setup a data_table_region + * + * MUTEX: Assumes namespace is not locked + * + ******************************************************************************/ + +acpi_status +acpi_ev_data_table_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context) +{ + union acpi_operand_object *region_desc = + (union acpi_operand_object *)handle; + struct acpi_data_table_space_context *local_region_context; + + ACPI_FUNCTION_TRACE(ev_data_table_region_setup); + + if (function == ACPI_REGION_DEACTIVATE) { + if (*region_context) { + ACPI_FREE(*region_context); + *region_context = NULL; + } + return_ACPI_STATUS(AE_OK); + } + + /* Create a new context */ + + local_region_context = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_data_table_space_context)); + if (!(local_region_context)) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Save the data table pointer for use in the handler */ + + local_region_context->pointer = region_desc->region.pointer; + + *region_context = local_region_context; + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * * FUNCTION: acpi_ev_default_region_setup * * PARAMETERS: handle - Region we are interested in diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 0cd9b3738e76..6c2685a6a4c1 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -411,7 +411,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, acpi_ex_exit_interpreter(); status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, - TRUE, &table_index); + table, TRUE, &table_index); acpi_ex_enter_interpreter(); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 80b52ad55775..deb3674ae726 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -279,6 +279,7 @@ acpi_ex_create_region(u8 * aml_start, obj_desc->region.space_id = space_id; obj_desc->region.address = 0; obj_desc->region.length = 0; + obj_desc->region.pointer = NULL; obj_desc->region.node = node; obj_desc->region.handler = NULL; obj_desc->common.flags &= diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 06f3c9df1e22..8618500f23b3 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -330,12 +330,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, obj_desc->field.base_byte_offset, source_desc->buffer.pointer, data_length); - if ((obj_desc->field.region_obj->region.address == - PCC_MASTER_SUBSPACE - && MASTER_SUBSPACE_COMMAND(obj_desc->field. - base_byte_offset)) - || GENERIC_SUBSPACE_COMMAND(obj_desc->field. - base_byte_offset)) { + if (MASTER_SUBSPACE_COMMAND(obj_desc->field.base_byte_offset)) { /* Perform the write */ diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index b639e930d642..44b7c350ed5c 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -1007,7 +1007,8 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) (walk_state, return_desc, &temp_desc); if (ACPI_FAILURE(status)) { - goto cleanup; + return_ACPI_STATUS + (status); } return_desc = temp_desc; diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 82b713a9a193..48c19908fa4e 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -509,8 +509,15 @@ acpi_ex_data_table_space_handler(u32 function, u64 *value, void *handler_context, void *region_context) { + struct acpi_data_table_space_context *mapping; + char *pointer; + ACPI_FUNCTION_TRACE(ex_data_table_space_handler); + mapping = (struct acpi_data_table_space_context *) region_context; + pointer = ACPI_CAST_PTR(char, mapping->pointer) + + (address - ACPI_PTR_TO_PHYSADDR(mapping->pointer)); + /* * Perform the memory read or write. The bit_width was already * validated. @@ -518,14 +525,14 @@ acpi_ex_data_table_space_handler(u32 function, switch (function) { case ACPI_READ: - memcpy(ACPI_CAST_PTR(char, value), - ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width)); + memcpy(ACPI_CAST_PTR(char, value), pointer, + ACPI_DIV_8(bit_width)); break; case ACPI_WRITE: - memcpy(ACPI_PHYSADDR_TO_PTR(address), - ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width)); + memcpy(pointer, ACPI_CAST_PTR(char, value), + ACPI_DIV_8(bit_width)); break; default: diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 808fdf54aeeb..7ee2939c08cd 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -104,7 +104,9 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) /* Flush caches, as per ACPI specification */ - ACPI_FLUSH_CPU_CACHE(); + if (sleep_state < ACPI_STATE_S4) { + ACPI_FLUSH_CPU_CACHE(); + } status = acpi_os_enter_sleep(sleep_state, sleep_control, 0); if (status == AE_CTRL_TERMINATE) { diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 34a3825f25d3..5efa3d8e483e 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -110,7 +110,9 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) /* Flush caches, as per ACPI specification */ - ACPI_FLUSH_CPU_CACHE(); + if (sleep_state < ACPI_STATE_S4) { + ACPI_FLUSH_CPU_CACHE(); + } status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control); if (status == AE_CTRL_TERMINATE) { diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index e4cde23a2906..ba77598ee43e 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -162,8 +162,6 @@ acpi_status acpi_enter_sleep_state_s4bios(void) return_ACPI_STATUS(status); } - ACPI_FLUSH_CPU_CACHE(); - status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, (u32)acpi_gbl_FADT.s4_bios_request, 8); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index ebbca109edcb..20360a9db482 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -89,14 +89,27 @@ acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, { /* - * Initialize the table descriptor. Set the pointer to NULL, since the - * table is not fully mapped at this time. + * Initialize the table descriptor. Set the pointer to NULL for external + * tables, since the table is not fully mapped at this time. */ memset(table_desc, 0, sizeof(struct acpi_table_desc)); table_desc->address = address; table_desc->length = table->length; table_desc->flags = flags; ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); + + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + + table_desc->pointer = table; + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + default: + + break; + } } /******************************************************************************* @@ -132,9 +145,7 @@ acpi_tb_acquire_table(struct acpi_table_desc *table_desc, case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: - table = ACPI_CAST_PTR(struct acpi_table_header, - ACPI_PHYSADDR_TO_PTR(table_desc-> - address)); + table = table_desc->pointer; break; default: @@ -196,6 +207,8 @@ acpi_tb_release_table(struct acpi_table_header *table, * PARAMETERS: table_desc - Table descriptor to be acquired * address - Address of the table * flags - Allocation flags of the table + * table - Pointer to the table (required for virtual + * origins, optional for physical) * * RETURN: Status * @@ -208,49 +221,52 @@ acpi_tb_release_table(struct acpi_table_header *table, acpi_status acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, - acpi_physical_address address, u8 flags) + acpi_physical_address address, + u8 flags, struct acpi_table_header *table) { - struct acpi_table_header *table_header; + u8 mapped_table = FALSE; switch (flags & ACPI_TABLE_ORIGIN_MASK) { case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: /* Get the length of the full table from the header */ - table_header = - acpi_os_map_memory(address, - sizeof(struct acpi_table_header)); - if (!table_header) { - return (AE_NO_MEMORY); + if (!table) { + table = + acpi_os_map_memory(address, + sizeof(struct + acpi_table_header)); + if (!table) { + return (AE_NO_MEMORY); + } + + mapped_table = TRUE; } - acpi_tb_init_table_descriptor(table_desc, address, flags, - table_header); - acpi_os_unmap_memory(table_header, - sizeof(struct acpi_table_header)); - return (AE_OK); + break; case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: - table_header = ACPI_CAST_PTR(struct acpi_table_header, - ACPI_PHYSADDR_TO_PTR(address)); - if (!table_header) { - return (AE_NO_MEMORY); + if (!table) { + return (AE_BAD_PARAMETER); } - acpi_tb_init_table_descriptor(table_desc, address, flags, - table_header); - return (AE_OK); + break; default: - break; + /* Table is not valid yet */ + + return (AE_NO_MEMORY); } - /* Table is not valid yet */ + acpi_tb_init_table_descriptor(table_desc, address, flags, table); + if (mapped_table) { + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + } - return (AE_NO_MEMORY); + return (AE_OK); } /******************************************************************************* @@ -335,7 +351,19 @@ void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) acpi_tb_release_table(table_desc->pointer, table_desc->length, table_desc->flags); - table_desc->pointer = NULL; + + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + table_desc->pointer = NULL; + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + default: + + break; + } return_VOID; } @@ -959,6 +987,9 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node) * * PARAMETERS: address - Physical address of the table * flags - Allocation flags of the table + * table - Pointer to the table (required for + * virtual origins, optional for + * physical) * override - Whether override should be performed * table_index - Where table index is returned * @@ -970,7 +1001,9 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node) acpi_status acpi_tb_install_and_load_table(acpi_physical_address address, - u8 flags, u8 override, u32 *table_index) + u8 flags, + struct acpi_table_header *table, + u8 override, u32 *table_index) { acpi_status status; u32 i; @@ -979,7 +1012,7 @@ acpi_tb_install_and_load_table(acpi_physical_address address, /* Install the table and load it into the namespace */ - status = acpi_tb_install_standard_table(address, flags, TRUE, + status = acpi_tb_install_standard_table(address, flags, table, TRUE, override, &i); if (ACPI_FAILURE(status)) { goto exit; diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 5174abfa8af9..047bd094ba68 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -313,7 +313,7 @@ void acpi_tb_parse_fadt(void) acpi_tb_install_standard_table((acpi_physical_address)acpi_gbl_FADT. Xdsdt, ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, - FALSE, TRUE, &acpi_gbl_dsdt_index); + NULL, FALSE, TRUE, &acpi_gbl_dsdt_index); /* If Hardware Reduced flag is set, there is no FACS */ @@ -322,14 +322,14 @@ void acpi_tb_parse_fadt(void) acpi_tb_install_standard_table((acpi_physical_address) acpi_gbl_FADT.facs, ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, - FALSE, TRUE, + NULL, FALSE, TRUE, &acpi_gbl_facs_index); } if (acpi_gbl_FADT.Xfacs) { acpi_tb_install_standard_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, - FALSE, TRUE, + NULL, FALSE, TRUE, &acpi_gbl_xfacs_index); } } diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 8d1e5b572493..5649f493a1ed 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -79,6 +79,8 @@ acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, * PARAMETERS: address - Address of the table (might be a virtual * address depending on the table_flags) * flags - Flags for the table + * table - Pointer to the table (required for virtual + * origins, optional for physical) * reload - Whether reload should be performed * override - Whether override should be performed * table_index - Where the table index is returned @@ -96,6 +98,7 @@ acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, acpi_status acpi_tb_install_standard_table(acpi_physical_address address, u8 flags, + struct acpi_table_header *table, u8 reload, u8 override, u32 *table_index) { u32 i; @@ -106,7 +109,8 @@ acpi_tb_install_standard_table(acpi_physical_address address, /* Acquire a temporary table descriptor for validation */ - status = acpi_tb_acquire_temp_table(&new_table_desc, address, flags); + status = + acpi_tb_acquire_temp_table(&new_table_desc, address, flags, table); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not acquire table length at %8.8X%8.8X", @@ -209,7 +213,8 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) if (ACPI_SUCCESS(status) && table) { acpi_tb_acquire_temp_table(&new_table_desc, ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL); + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, + table); ACPI_ERROR_ONLY(override_type = "Logical"); goto finish_override; } @@ -220,7 +225,8 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) &address, &length); if (ACPI_SUCCESS(status) && address && length) { acpi_tb_acquire_temp_table(&new_table_desc, address, - ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, + NULL); ACPI_ERROR_ONLY(override_type = "Physical"); goto finish_override; } @@ -289,7 +295,8 @@ void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) { - ACPI_FREE(ACPI_PHYSADDR_TO_PTR(table_desc->address)); + ACPI_FREE(table_desc->pointer); + table_desc->pointer = NULL; } table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index 254823d494a2..4dac16bd63d3 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -101,7 +101,8 @@ acpi_tb_print_table_header(acpi_physical_address address, ACPI_INFO(("%-4.4s 0x%8.8X%8.8X %06X", header->signature, ACPI_FORMAT_UINT64(address), header->length)); - } else if (ACPI_VALIDATE_RSDP_SIG(header->signature)) { + } else if (ACPI_VALIDATE_RSDP_SIG(ACPI_CAST_PTR(struct acpi_table_rsdp, + header)->signature)) { /* RSDP has no common fields */ diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 4b9b329a5a92..5e8d50a4b6a9 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -328,7 +328,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address) status = acpi_tb_install_standard_table(address, ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, - FALSE, TRUE, + NULL, FALSE, TRUE, &table_index); if (ACPI_SUCCESS(status) && diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 38623049b962..87356d9ad613 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -227,9 +227,7 @@ unlock_and_exit: * * FUNCTION: acpi_install_table * - * PARAMETERS: address - Address of the ACPI table to be installed. - * physical - Whether the address is a physical table - * address or not + * PARAMETERS: table - Pointer to the ACPI table to be installed. * * RETURN: Status * @@ -240,22 +238,17 @@ unlock_and_exit: ******************************************************************************/ acpi_status ACPI_INIT_FUNCTION -acpi_install_table(acpi_physical_address address, u8 physical) +acpi_install_table(struct acpi_table_header *table) { acpi_status status; - u8 flags; u32 table_index; ACPI_FUNCTION_TRACE(acpi_install_table); - if (physical) { - flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL; - } else { - flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL; - } - - status = acpi_tb_install_standard_table(address, flags, - FALSE, FALSE, &table_index); + status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, + table, FALSE, FALSE, + &table_index); return_ACPI_STATUS(status); } @@ -264,6 +257,37 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_install_table) /******************************************************************************* * + * FUNCTION: acpi_install_physical_table + * + * PARAMETERS: address - Address of the ACPI table to be installed. + * + * RETURN: Status + * + * DESCRIPTION: Dynamically install an ACPI table. + * Note: This function should only be invoked after + * acpi_initialize_tables() and before acpi_load_tables(). + * + ******************************************************************************/ +acpi_status ACPI_INIT_FUNCTION +acpi_install_physical_table(acpi_physical_address address) +{ + acpi_status status; + u32 table_index; + + ACPI_FUNCTION_TRACE(acpi_install_physical_table); + + status = acpi_tb_install_standard_table(address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, + NULL, FALSE, FALSE, + &table_index); + + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL_INIT(acpi_install_physical_table) + +/******************************************************************************* + * * FUNCTION: acpi_load_table * * PARAMETERS: table - Pointer to a buffer containing the ACPI @@ -298,7 +322,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table, u32 *table_idx) ACPI_INFO(("Host-directed Dynamic ACPI Table Load:")); status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, - FALSE, &table_index); + table, FALSE, &table_index); if (table_idx) { *table_idx = table_index; } diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index e5ba9795ec69..8d7736d2d269 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -422,6 +422,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) ACPI_WARNING((AE_INFO, "Obj %p, Reference Count is already zero, cannot decrement\n", object)); + return; } ACPI_DEBUG_PRINT_RAW((ACPI_DB_ALLOCATIONS, diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index dd535b4b9a16..75a61626eddd 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1320,6 +1320,7 @@ static int __init acpi_init(void) pr_debug("%s: kset create error\n", __func__); init_prmt(); + acpi_init_pcc(); result = acpi_bus_init(); if (result) { kobject_put(acpi_kobj); diff --git a/drivers/acpi/dptf/dptf_pch_fivr.c b/drivers/acpi/dptf/dptf_pch_fivr.c index f4e9c2ef2f88..e7ab0fc90db9 100644 --- a/drivers/acpi/dptf/dptf_pch_fivr.c +++ b/drivers/acpi/dptf/dptf_pch_fivr.c @@ -46,7 +46,7 @@ release_buffer: } /* - * Presentation of attributes which are defined for INT1045 + * Presentation of attributes which are defined for INTC10xx * They are: * freq_mhz_low_clock : Set PCH FIVR switching freq for * FIVR clock 19.2MHz and 24MHz diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a6366d3f0c78..0077d2c85df8 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -92,8 +92,6 @@ enum ec_command { enum { EC_FLAGS_QUERY_ENABLED, /* Query is enabled */ - EC_FLAGS_QUERY_PENDING, /* Query is pending */ - EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */ EC_FLAGS_EVENT_HANDLER_INSTALLED, /* Event handler installed */ EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */ EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */ @@ -166,12 +164,12 @@ struct acpi_ec_query { struct transaction transaction; struct work_struct work; struct acpi_ec_query_handler *handler; + struct acpi_ec *ec; }; -static int acpi_ec_query(struct acpi_ec *ec, u8 *data); -static void advance_transaction(struct acpi_ec *ec, bool interrupt); +static int acpi_ec_submit_query(struct acpi_ec *ec); +static bool advance_transaction(struct acpi_ec *ec, bool interrupt); static void acpi_ec_event_handler(struct work_struct *work); -static void acpi_ec_event_processor(struct work_struct *work); struct acpi_ec *first_ec; EXPORT_SYMBOL(first_ec); @@ -443,24 +441,51 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) return true; } -static void acpi_ec_submit_query(struct acpi_ec *ec) +static bool acpi_ec_submit_event(struct acpi_ec *ec) { acpi_ec_mask_events(ec); if (!acpi_ec_event_enabled(ec)) - return; - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { + return false; + + if (ec->event_state == EC_EVENT_READY) { ec_dbg_evt("Command(%s) submitted/blocked", acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); - ec->nr_pending_queries++; - queue_work(ec_wq, &ec->work); + + ec->event_state = EC_EVENT_IN_PROGRESS; + /* + * If events_to_process is greqter than 0 at this point, the + * while () loop in acpi_ec_event_handler() is still running + * and incrementing events_to_process will cause it to invoke + * acpi_ec_submit_query() once more, so it is not necessary to + * queue up the event work to start the same loop again. + */ + if (ec->events_to_process++ > 0) + return true; + + ec->events_in_progress++; + return queue_work(ec_wq, &ec->work); } + + /* + * The event handling work has not been completed yet, so it needs to be + * flushed. + */ + return true; +} + +static void acpi_ec_complete_event(struct acpi_ec *ec) +{ + if (ec->event_state == EC_EVENT_IN_PROGRESS) + ec->event_state = EC_EVENT_COMPLETE; } -static void acpi_ec_complete_query(struct acpi_ec *ec) +static void acpi_ec_close_event(struct acpi_ec *ec) { - if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) + if (ec->event_state != EC_EVENT_READY) ec_dbg_evt("Command(%s) unblocked", acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); + + ec->event_state = EC_EVENT_READY; acpi_ec_unmask_events(ec); } @@ -487,12 +512,10 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec) */ static void acpi_ec_clear(struct acpi_ec *ec) { - int i, status; - u8 value = 0; + int i; for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { - status = acpi_ec_query(ec, &value); - if (status || !value) + if (acpi_ec_submit_query(ec)) break; } if (unlikely(i == ACPI_EC_CLEAR_MAX)) @@ -518,7 +541,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) #ifdef CONFIG_PM_SLEEP static void __acpi_ec_flush_work(void) { - drain_workqueue(ec_wq); /* flush ec->work */ + flush_workqueue(ec_wq); /* flush ec->work */ flush_workqueue(ec_query_wq); /* flush queries */ } @@ -549,8 +572,8 @@ void acpi_ec_flush_work(void) static bool acpi_ec_guard_event(struct acpi_ec *ec) { - bool guarded = true; unsigned long flags; + bool guarded; spin_lock_irqsave(&ec->lock, flags); /* @@ -559,19 +582,15 @@ static bool acpi_ec_guard_event(struct acpi_ec *ec) * evaluating _Qxx, so we need to re-check SCI_EVT after waiting an * acceptable period. * - * The guarding period begins when EC_FLAGS_QUERY_PENDING is - * flagged, which means SCI_EVT check has just been performed. - * But if the current transaction is ACPI_EC_COMMAND_QUERY, the - * guarding should have already been performed (via - * EC_FLAGS_QUERY_GUARDING) and should not be applied so that the - * ACPI_EC_COMMAND_QUERY transaction can be transitioned into - * ACPI_EC_COMMAND_POLL state immediately. + * The guarding period is applicable if the event state is not + * EC_EVENT_READY, but otherwise if the current transaction is of the + * ACPI_EC_COMMAND_QUERY type, the guarding should have elapsed already + * and it should not be applied to let the transaction transition into + * the ACPI_EC_COMMAND_POLL state immediately. */ - if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS || - ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY || - !test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags) || - (ec->curr && ec->curr->command == ACPI_EC_COMMAND_QUERY)) - guarded = false; + guarded = ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && + ec->event_state != EC_EVENT_READY && + (!ec->curr || ec->curr->command != ACPI_EC_COMMAND_QUERY); spin_unlock_irqrestore(&ec->lock, flags); return guarded; } @@ -603,16 +622,26 @@ static int ec_transaction_completed(struct acpi_ec *ec) static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long flag) { ec->curr->flags |= flag; - if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { - if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS && - flag == ACPI_EC_COMMAND_POLL) - acpi_ec_complete_query(ec); - if (ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY && - flag == ACPI_EC_COMMAND_COMPLETE) - acpi_ec_complete_query(ec); - if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && - flag == ACPI_EC_COMMAND_COMPLETE) - set_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags); + + if (ec->curr->command != ACPI_EC_COMMAND_QUERY) + return; + + switch (ec_event_clearing) { + case ACPI_EC_EVT_TIMING_STATUS: + if (flag == ACPI_EC_COMMAND_POLL) + acpi_ec_close_event(ec); + + return; + + case ACPI_EC_EVT_TIMING_QUERY: + if (flag == ACPI_EC_COMMAND_COMPLETE) + acpi_ec_close_event(ec); + + return; + + case ACPI_EC_EVT_TIMING_EVENT: + if (flag == ACPI_EC_COMMAND_COMPLETE) + acpi_ec_complete_event(ec); } } @@ -626,10 +655,11 @@ static void acpi_ec_spurious_interrupt(struct acpi_ec *ec, struct transaction *t acpi_ec_mask_events(ec); } -static void advance_transaction(struct acpi_ec *ec, bool interrupt) +static bool advance_transaction(struct acpi_ec *ec, bool interrupt) { struct transaction *t = ec->curr; bool wakeup = false; + bool ret = false; u8 status; ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id()); @@ -657,11 +687,9 @@ static void advance_transaction(struct acpi_ec *ec, bool interrupt) */ if (!t || !(t->flags & ACPI_EC_COMMAND_POLL)) { if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && - (!ec->nr_pending_queries || - test_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags))) { - clear_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags); - acpi_ec_complete_query(ec); - } + ec->event_state == EC_EVENT_COMPLETE) + acpi_ec_close_event(ec); + if (!t) goto out; } @@ -696,10 +724,12 @@ static void advance_transaction(struct acpi_ec *ec, bool interrupt) out: if (status & ACPI_EC_FLAG_SCI) - acpi_ec_submit_query(ec); + ret = acpi_ec_submit_event(ec); if (wakeup && interrupt) wake_up(&ec->wait); + + return ret; } static void start_transaction(struct acpi_ec *ec) @@ -1103,7 +1133,30 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) } EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); -static struct acpi_ec_query *acpi_ec_create_query(u8 *pval) +static void acpi_ec_event_processor(struct work_struct *work) +{ + struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work); + struct acpi_ec_query_handler *handler = q->handler; + struct acpi_ec *ec = q->ec; + + ec_dbg_evt("Query(0x%02x) started", handler->query_bit); + + if (handler->func) + handler->func(handler->data); + else if (handler->handle) + acpi_evaluate_object(handler->handle, NULL, NULL, NULL); + + ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit); + + spin_lock_irq(&ec->lock); + ec->queries_in_progress--; + spin_unlock_irq(&ec->lock); + + acpi_ec_put_query_handler(handler); + kfree(q); +} + +static struct acpi_ec_query *acpi_ec_create_query(struct acpi_ec *ec, u8 *pval) { struct acpi_ec_query *q; struct transaction *t; @@ -1111,44 +1164,23 @@ static struct acpi_ec_query *acpi_ec_create_query(u8 *pval) q = kzalloc(sizeof (struct acpi_ec_query), GFP_KERNEL); if (!q) return NULL; + INIT_WORK(&q->work, acpi_ec_event_processor); t = &q->transaction; t->command = ACPI_EC_COMMAND_QUERY; t->rdata = pval; t->rlen = 1; + q->ec = ec; return q; } -static void acpi_ec_delete_query(struct acpi_ec_query *q) -{ - if (q) { - if (q->handler) - acpi_ec_put_query_handler(q->handler); - kfree(q); - } -} - -static void acpi_ec_event_processor(struct work_struct *work) -{ - struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work); - struct acpi_ec_query_handler *handler = q->handler; - - ec_dbg_evt("Query(0x%02x) started", handler->query_bit); - if (handler->func) - handler->func(handler->data); - else if (handler->handle) - acpi_evaluate_object(handler->handle, NULL, NULL, NULL); - ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit); - acpi_ec_delete_query(q); -} - -static int acpi_ec_query(struct acpi_ec *ec, u8 *data) +static int acpi_ec_submit_query(struct acpi_ec *ec) { + struct acpi_ec_query *q; u8 value = 0; int result; - struct acpi_ec_query *q; - q = acpi_ec_create_query(&value); + q = acpi_ec_create_query(ec, &value); if (!q) return -ENOMEM; @@ -1158,11 +1190,14 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data) * bit to be cleared (and thus clearing the interrupt source). */ result = acpi_ec_transaction(ec, &q->transaction); - if (!value) - result = -ENODATA; if (result) goto err_exit; + if (!value) { + result = -ENODATA; + goto err_exit; + } + q->handler = acpi_ec_get_query_handler_by_value(ec, value); if (!q->handler) { result = -ENODATA; @@ -1170,76 +1205,73 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data) } /* - * It is reported that _Qxx are evaluated in a parallel way on - * Windows: + * It is reported that _Qxx are evaluated in a parallel way on Windows: * https://bugzilla.kernel.org/show_bug.cgi?id=94411 * - * Put this log entry before schedule_work() in order to make - * it appearing before any other log entries occurred during the - * work queue execution. + * Put this log entry before queue_work() to make it appear in the log + * before any other messages emitted during workqueue handling. */ ec_dbg_evt("Query(0x%02x) scheduled", value); - if (!queue_work(ec_query_wq, &q->work)) { - ec_dbg_evt("Query(0x%02x) overlapped", value); - result = -EBUSY; - } -err_exit: - if (result) - acpi_ec_delete_query(q); - if (data) - *data = value; - return result; -} + spin_lock_irq(&ec->lock); -static void acpi_ec_check_event(struct acpi_ec *ec) -{ - unsigned long flags; + ec->queries_in_progress++; + queue_work(ec_query_wq, &q->work); - if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) { - if (ec_guard(ec)) { - spin_lock_irqsave(&ec->lock, flags); - /* - * Take care of the SCI_EVT unless no one else is - * taking care of it. - */ - if (!ec->curr) - advance_transaction(ec, false); - spin_unlock_irqrestore(&ec->lock, flags); - } - } + spin_unlock_irq(&ec->lock); + + return 0; + +err_exit: + kfree(q); + + return result; } static void acpi_ec_event_handler(struct work_struct *work) { - unsigned long flags; struct acpi_ec *ec = container_of(work, struct acpi_ec, work); ec_dbg_evt("Event started"); - spin_lock_irqsave(&ec->lock, flags); - while (ec->nr_pending_queries) { - spin_unlock_irqrestore(&ec->lock, flags); - (void)acpi_ec_query(ec, NULL); - spin_lock_irqsave(&ec->lock, flags); - ec->nr_pending_queries--; - /* - * Before exit, make sure that this work item can be - * scheduled again. There might be QR_EC failures, leaving - * EC_FLAGS_QUERY_PENDING uncleared and preventing this work - * item from being scheduled again. - */ - if (!ec->nr_pending_queries) { - if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS || - ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY) - acpi_ec_complete_query(ec); - } + spin_lock_irq(&ec->lock); + + while (ec->events_to_process) { + spin_unlock_irq(&ec->lock); + + acpi_ec_submit_query(ec); + + spin_lock_irq(&ec->lock); + ec->events_to_process--; } - spin_unlock_irqrestore(&ec->lock, flags); + + /* + * Before exit, make sure that the it will be possible to queue up the + * event handling work again regardless of whether or not the query + * queued up above is processed successfully. + */ + if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) + acpi_ec_complete_event(ec); + else + acpi_ec_close_event(ec); + + spin_unlock_irq(&ec->lock); ec_dbg_evt("Event stopped"); - acpi_ec_check_event(ec); + if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && ec_guard(ec)) { + spin_lock_irq(&ec->lock); + + /* Take care of SCI_EVT unless someone else is doing that. */ + if (!ec->curr) + advance_transaction(ec, false); + + spin_unlock_irq(&ec->lock); + } + + spin_lock_irq(&ec->lock); + ec->events_in_progress--; + spin_unlock_irq(&ec->lock); } static void acpi_ec_handle_interrupt(struct acpi_ec *ec) @@ -2021,7 +2053,7 @@ void acpi_ec_set_gpe_wake_mask(u8 action) bool acpi_ec_dispatch_gpe(void) { - u32 ret; + bool work_in_progress = false; if (!first_ec) return acpi_any_gpe_status_set(U32_MAX); @@ -2037,12 +2069,31 @@ bool acpi_ec_dispatch_gpe(void) * Dispatch the EC GPE in-band, but do not report wakeup in any case * to allow the caller to process events properly after that. */ - ret = acpi_dispatch_gpe(NULL, first_ec->gpe); - if (ret == ACPI_INTERRUPT_HANDLED) - pm_pr_dbg("ACPI EC GPE dispatched\n"); + spin_lock_irq(&first_ec->lock); + + if (acpi_ec_gpe_status_set(first_ec)) + work_in_progress = advance_transaction(first_ec, false); + + spin_unlock_irq(&first_ec->lock); + + if (!work_in_progress) + return false; + + pm_pr_dbg("ACPI EC GPE dispatched\n"); + + /* Drain EC work. */ + do { + acpi_ec_flush_work(); + + pm_pr_dbg("ACPI EC work flushed\n"); + + spin_lock_irq(&first_ec->lock); + + work_in_progress = first_ec->events_in_progress + + first_ec->queries_in_progress > 0; - /* Flush the event and query workqueues. */ - acpi_ec_flush_work(); + spin_unlock_irq(&first_ec->lock); + } while (work_in_progress && !pm_wakeup_pending()); return false; } diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index fd39c14493ab..c074a0fae059 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -19,7 +19,7 @@ MODULE_DESCRIPTION("ACPI EC sysfs access driver"); MODULE_LICENSE("GPL"); static bool write_support; -module_param(write_support, bool, 0644); +module_param_hw(write_support, bool, other, 0644); MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may " "be needed."); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index d91b560e8867..1db3a2f81763 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -166,6 +166,13 @@ static inline void acpi_early_processor_osc(void) {} /* -------------------------------------------------------------------------- Embedded Controller -------------------------------------------------------------------------- */ + +enum acpi_ec_event_state { + EC_EVENT_READY = 0, /* Event work can be submitted */ + EC_EVENT_IN_PROGRESS, /* Event work is pending or being processed */ + EC_EVENT_COMPLETE, /* Event work processing has completed */ +}; + struct acpi_ec { acpi_handle handle; int gpe; @@ -182,7 +189,10 @@ struct acpi_ec { spinlock_t lock; struct work_struct work; unsigned long timestamp; - unsigned long nr_pending_queries; + enum acpi_ec_event_state event_state; + unsigned int events_to_process; + unsigned int events_in_progress; + unsigned int queries_in_progress; bool busy_polling; unsigned int polling_guard; }; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 41a8fef06534..b76db99cced3 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -322,7 +322,7 @@ EXPORT_SYMBOL_GPL(acpi_get_pci_dev); * acpi_pci_osc_control_set - Request control of PCI root _OSC features. * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex). * @mask: Mask of _OSC bits to request control of, place to store control mask. - * @req: Mask of _OSC bits the control of is essential to the caller. + * @support: _OSC supported capability. * * Run _OSC query for @mask and if that is successful, compare the returned * mask of control bits with @req. If all of the @req bits are set in the diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c index 9cde299eba88..f20dbda1a831 100644 --- a/drivers/acpi/pmic/intel_pmic.c +++ b/drivers/acpi/pmic/intel_pmic.c @@ -25,7 +25,7 @@ struct intel_pmic_opregion { struct mutex lock; struct acpi_lpat_conversion_table *lpat_table; struct regmap *regmap; - struct intel_pmic_opregion_data *data; + const struct intel_pmic_opregion_data *data; struct intel_pmic_regs_handler_ctx ctx; }; @@ -53,7 +53,7 @@ static acpi_status intel_pmic_power_handler(u32 function, { struct intel_pmic_opregion *opregion = region_context; struct regmap *regmap = opregion->regmap; - struct intel_pmic_opregion_data *d = opregion->data; + const struct intel_pmic_opregion_data *d = opregion->data; int reg, bit, result; if (bits != 32 || !value64) @@ -95,7 +95,7 @@ static int pmic_read_temp(struct intel_pmic_opregion *opregion, return 0; } - temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp); + temp = opregion->data->lpat_raw_to_temp(opregion->lpat_table, raw_temp); if (temp < 0) return temp; @@ -135,7 +135,7 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg, static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg, int bit, u32 function, u64 *value) { - struct intel_pmic_opregion_data *d = opregion->data; + const struct intel_pmic_opregion_data *d = opregion->data; struct regmap *regmap = opregion->regmap; if (!d->get_policy || !d->update_policy) @@ -171,7 +171,7 @@ static acpi_status intel_pmic_thermal_handler(u32 function, void *handler_context, void *region_context) { struct intel_pmic_opregion *opregion = region_context; - struct intel_pmic_opregion_data *d = opregion->data; + const struct intel_pmic_opregion_data *d = opregion->data; int reg, bit, result; if (bits != 32 || !value64) @@ -255,7 +255,7 @@ static acpi_status intel_pmic_regs_handler(u32 function, int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, struct regmap *regmap, - struct intel_pmic_opregion_data *d) + const struct intel_pmic_opregion_data *d) { acpi_status status = AE_OK; struct intel_pmic_opregion *opregion; @@ -344,7 +344,7 @@ EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address, u32 value, u32 mask) { - struct intel_pmic_opregion_data *d; + const struct intel_pmic_opregion_data *d; int ret; if (!intel_pmic_opregion) { diff --git a/drivers/acpi/pmic/intel_pmic.h b/drivers/acpi/pmic/intel_pmic.h index 89379476a1df..d956b03a6ca0 100644 --- a/drivers/acpi/pmic/intel_pmic.h +++ b/drivers/acpi/pmic/intel_pmic.h @@ -2,6 +2,8 @@ #ifndef __INTEL_PMIC_H #define __INTEL_PMIC_H +#include <acpi/acpi_lpat.h> + struct pmic_table { int address; /* operation region address */ int reg; /* corresponding thermal register */ @@ -17,6 +19,8 @@ struct intel_pmic_opregion_data { int (*update_policy)(struct regmap *r, int reg, int bit, int enable); int (*exec_mipi_pmic_seq_element)(struct regmap *r, u16 i2c_address, u32 reg_address, u32 value, u32 mask); + int (*lpat_raw_to_temp)(struct acpi_lpat_conversion_table *lpat_table, + int raw); struct pmic_table *power_table; int power_table_count; struct pmic_table *thermal_table; @@ -25,6 +29,8 @@ struct intel_pmic_opregion_data { int pmic_i2c_address; }; -int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, struct regmap *regmap, struct intel_pmic_opregion_data *d); +int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, + struct regmap *regmap, + const struct intel_pmic_opregion_data *d); #endif diff --git a/drivers/acpi/pmic/intel_pmic_bxtwc.c b/drivers/acpi/pmic/intel_pmic_bxtwc.c index bd7621edd60b..e247615189fa 100644 --- a/drivers/acpi/pmic/intel_pmic_bxtwc.c +++ b/drivers/acpi/pmic/intel_pmic_bxtwc.c @@ -369,13 +369,14 @@ intel_bxtwc_pmic_update_policy(struct regmap *regmap, return regmap_update_bits(regmap, reg, mask, val); } -static struct intel_pmic_opregion_data intel_bxtwc_pmic_opregion_data = { +static const struct intel_pmic_opregion_data intel_bxtwc_pmic_opregion_data = { .get_power = intel_bxtwc_pmic_get_power, .update_power = intel_bxtwc_pmic_update_power, .get_raw_temp = intel_bxtwc_pmic_get_raw_temp, .update_aux = intel_bxtwc_pmic_update_aux, .get_policy = intel_bxtwc_pmic_get_policy, .update_policy = intel_bxtwc_pmic_update_policy, + .lpat_raw_to_temp = acpi_lpat_raw_to_temp, .power_table = power_table, .power_table_count = ARRAY_SIZE(power_table), .thermal_table = thermal_table, diff --git a/drivers/acpi/pmic/intel_pmic_bytcrc.c b/drivers/acpi/pmic/intel_pmic_bytcrc.c index 2a692cc4b7ae..9ea79f210965 100644 --- a/drivers/acpi/pmic/intel_pmic_bytcrc.c +++ b/drivers/acpi/pmic/intel_pmic_bytcrc.c @@ -271,13 +271,14 @@ static int intel_crc_pmic_update_policy(struct regmap *regmap, return 0; } -static struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = { +static const struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = { .get_power = intel_crc_pmic_get_power, .update_power = intel_crc_pmic_update_power, .get_raw_temp = intel_crc_pmic_get_raw_temp, .update_aux = intel_crc_pmic_update_aux, .get_policy = intel_crc_pmic_get_policy, .update_policy = intel_crc_pmic_update_policy, + .lpat_raw_to_temp = acpi_lpat_raw_to_temp, .power_table = power_table, .power_table_count= ARRAY_SIZE(power_table), .thermal_table = thermal_table, diff --git a/drivers/acpi/pmic/intel_pmic_chtcrc.c b/drivers/acpi/pmic/intel_pmic_chtcrc.c index 2900dc3074d2..f9301c6f098e 100644 --- a/drivers/acpi/pmic/intel_pmic_chtcrc.c +++ b/drivers/acpi/pmic/intel_pmic_chtcrc.c @@ -23,7 +23,8 @@ * intel_soc_pmic_exec_mipi_pmic_seq_element work on devices with a * CHT Crystal Cove PMIC. */ -static struct intel_pmic_opregion_data intel_chtcrc_pmic_opregion_data = { +static const struct intel_pmic_opregion_data intel_chtcrc_pmic_opregion_data = { + .lpat_raw_to_temp = acpi_lpat_raw_to_temp, .pmic_i2c_address = 0x6e, }; diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c index fef7831d0d63..418eec523025 100644 --- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c +++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c @@ -94,10 +94,11 @@ static int chtdc_ti_pmic_get_raw_temp(struct regmap *regmap, int reg) return ((buf[0] & 0x03) << 8) | buf[1]; } -static struct intel_pmic_opregion_data chtdc_ti_pmic_opregion_data = { +static const struct intel_pmic_opregion_data chtdc_ti_pmic_opregion_data = { .get_power = chtdc_ti_pmic_get_power, .update_power = chtdc_ti_pmic_update_power, .get_raw_temp = chtdc_ti_pmic_get_raw_temp, + .lpat_raw_to_temp = acpi_lpat_raw_to_temp, .power_table = chtdc_ti_power_table, .power_table_count = ARRAY_SIZE(chtdc_ti_power_table), .thermal_table = chtdc_ti_thermal_table, diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c index 7ffd5624b8e1..f2c42f4c79ca 100644 --- a/drivers/acpi/pmic/intel_pmic_chtwc.c +++ b/drivers/acpi/pmic/intel_pmic_chtwc.c @@ -253,10 +253,11 @@ static int intel_cht_wc_exec_mipi_pmic_seq_element(struct regmap *regmap, * The thermal table and ops are empty, we do not support the Thermal opregion * (DPTF) due to lacking documentation. */ -static struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = { +static const struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = { .get_power = intel_cht_wc_pmic_get_power, .update_power = intel_cht_wc_pmic_update_power, .exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element, + .lpat_raw_to_temp = acpi_lpat_raw_to_temp, .power_table = power_table, .power_table_count = ARRAY_SIZE(power_table), }; diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index cbe08e600fa3..61bbe4c24d87 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -293,11 +293,33 @@ static int intel_xpower_exec_mipi_pmic_seq_element(struct regmap *regmap, return ret; } -static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { +static int intel_xpower_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, + int raw) +{ + struct acpi_lpat first = lpat_table->lpat[0]; + struct acpi_lpat last = lpat_table->lpat[lpat_table->lpat_count - 1]; + + /* + * Some LPAT tables in the ACPI Device for the AXP288 PMIC for some + * reason only describe a small temperature range, e.g. 27° - 37° + * Celcius. Resulting in errors when the tablet is idle in a cool room. + * + * To avoid these errors clamp the raw value to be inside the LPAT. + */ + if (first.raw < last.raw) + raw = clamp(raw, first.raw, last.raw); + else + raw = clamp(raw, last.raw, first.raw); + + return acpi_lpat_raw_to_temp(lpat_table, raw); +} + +static const struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { .get_power = intel_xpower_pmic_get_power, .update_power = intel_xpower_pmic_update_power, .get_raw_temp = intel_xpower_pmic_get_raw_temp, .exec_mipi_pmic_seq_element = intel_xpower_exec_mipi_pmic_seq_element, + .lpat_raw_to_temp = intel_xpower_lpat_raw_to_temp, .power_table = power_table, .power_table_count = ARRAY_SIZE(power_table), .thermal_table = thermal_table, diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 7e50bbfff1e0..8c4a73a1351e 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -716,6 +716,9 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) mutex_lock(&acpi_device_lock); + dev_dbg(&dev->dev, "Enabling wakeup power (count %d)\n", + dev->wakeup.prepare_count); + if (dev->wakeup.prepare_count++) goto out; @@ -734,8 +737,11 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) if (err) { acpi_power_off_list(&dev->wakeup.resources); dev->wakeup.prepare_count = 0; + goto out; } + dev_dbg(&dev->dev, "Wakeup power enabled\n"); + out: mutex_unlock(&acpi_device_lock); return err; @@ -757,6 +763,9 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) mutex_lock(&acpi_device_lock); + dev_dbg(&dev->dev, "Disabling wakeup power (count %d)\n", + dev->wakeup.prepare_count); + /* Do nothing if wakeup power has not been enabled for this device. */ if (dev->wakeup.prepare_count <= 0) goto out; @@ -782,8 +791,11 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) if (err) { dev_err(&dev->dev, "Cannot turn off wakeup power resources\n"); dev->wakeup.flags.valid = 0; + goto out; } + dev_dbg(&dev->dev, "Wakeup power disabled\n"); + out: mutex_unlock(&acpi_device_lock); return err; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ef17b95e5f37..86560a28751b 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -20,6 +20,7 @@ #include <linux/tick.h> #include <linux/cpuidle.h> #include <linux/cpu.h> +#include <linux/minmax.h> #include <acpi/processor.h> /* @@ -400,13 +401,10 @@ static int acpi_cst_latency_cmp(const void *a, const void *b) static void acpi_cst_latency_swap(void *a, void *b, int n) { struct acpi_processor_cx *x = a, *y = b; - u32 tmp; if (!(x->valid && y->valid)) return; - tmp = x->latency; - x->latency = y->latency; - y->latency = tmp; + swap(x->latency, y->latency); } static int acpi_processor_power_verify(struct acpi_processor *pr) @@ -567,7 +565,8 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) { struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); - ACPI_FLUSH_CPU_CACHE(); + if (cx->type == ACPI_STATE_C3) + ACPI_FLUSH_CPU_CACHE(); while (1) { diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index a3d34e3f9f94..d8b2dfcd59b5 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -53,10 +53,17 @@ static int phys_package_first_cpu(int cpu) static int cpu_has_cpufreq(unsigned int cpu) { - struct cpufreq_policy policy; - if (!acpi_processor_cpufreq_init || cpufreq_get_policy(&policy, cpu)) + struct cpufreq_policy *policy; + + if (!acpi_processor_cpufreq_init) return 0; - return 1; + + policy = cpufreq_cpu_get(cpu); + if (policy) { + cpufreq_cpu_put(policy); + return 1; + } + return 0; } static int cpufreq_get_max_state(unsigned int cpu) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index eaa47753b758..4b8454f26ca1 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -73,7 +73,6 @@ static int acpi_sleep_prepare(u32 acpi_state) acpi_set_waking_vector(acpi_wakeup_address); } - ACPI_FLUSH_CPU_CACHE(); #endif pr_info("Preparing to enter system sleep state S%d\n", acpi_state); acpi_enable_wakeup_devices(acpi_state); @@ -566,8 +565,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) u32 acpi_state = acpi_target_sleep_state; int error; - ACPI_FLUSH_CPU_CACHE(); - trace_suspend_resume(TPS("acpi_suspend"), acpi_state, true); switch (acpi_state) { case ACPI_STATE_S1: @@ -903,8 +900,6 @@ static int acpi_hibernation_enter(void) { acpi_status status = AE_OK; - ACPI_FLUSH_CPU_CACHE(); - /* This shouldn't return. If it returns, we have a problem */ status = acpi_enter_sleep_state(ACPI_STATE_S4); /* Reprogram control registers */ diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 71419eb16e09..2fa8f611d0a7 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -723,7 +723,7 @@ static void __init acpi_table_initrd_scan(void) /* * Mark the table to avoid being used in * acpi_table_initrd_override(). Though this is not possible - * because override is disabled in acpi_install_table(). + * because override is disabled in acpi_install_physical_table(). */ if (test_and_set_bit(table_index, acpi_initrd_installed)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); @@ -734,7 +734,7 @@ static void __init acpi_table_initrd_scan(void) table->signature, table->oem_id, table->oem_table_id); acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); - acpi_install_table(acpi_tables_addr + table_offset, TRUE); + acpi_install_physical_table(acpi_tables_addr + table_offset); next_table: table_offset += table_length; table_index++; |