diff options
Diffstat (limited to 'drivers')
45 files changed, 591 insertions, 161 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/acpi_video.c b/drivers/acpi/acpi_video.c index 42ede059728c..990ff5b0aeb8 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1733,13 +1733,12 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context, { struct acpi_device *device = context; struct acpi_device *sibling; - int result; if (handle == device->handle) return AE_CTRL_TERMINATE; - result = acpi_bus_get_device(handle, &sibling); - if (result) + sibling = acpi_fetch_acpi_dev(handle); + if (!sibling) return AE_OK; if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME)) 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 fa923a929224..b64014b4203e 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/device_pm.c b/drivers/acpi/device_pm.c index 19b33c028f35..cc6c97e7dcae 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -285,14 +285,12 @@ EXPORT_SYMBOL(acpi_device_set_power); int acpi_bus_set_power(acpi_handle handle, int state) { - struct acpi_device *device; - int result; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - result = acpi_bus_get_device(handle, &device); - if (result) - return result; + if (device) + return acpi_device_set_power(device, state); - return acpi_device_set_power(device, state); + return -ENODEV; } EXPORT_SYMBOL(acpi_bus_set_power); @@ -410,21 +408,20 @@ EXPORT_SYMBOL_GPL(acpi_device_update_power); int acpi_bus_update_power(acpi_handle handle, int *state_p) { - struct acpi_device *device; - int result; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - result = acpi_bus_get_device(handle, &device); - return result ? result : acpi_device_update_power(device, state_p); + if (device) + return acpi_device_update_power(device, state_p); + + return -ENODEV; } EXPORT_SYMBOL_GPL(acpi_bus_update_power); bool acpi_bus_power_manageable(acpi_handle handle) { - struct acpi_device *device; - int result; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - result = acpi_bus_get_device(handle, &device); - return result ? false : device->flags.power_manageable; + return device && device->flags.power_manageable; } EXPORT_SYMBOL(acpi_bus_power_manageable); @@ -543,11 +540,9 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev) bool acpi_bus_can_wakeup(acpi_handle handle) { - struct acpi_device *device; - int result; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - result = acpi_bus_get_device(handle, &device); - return result ? false : device->wakeup.flags.valid; + return device && device->wakeup.flags.valid; } EXPORT_SYMBOL(acpi_bus_can_wakeup); diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c8e9b962e18c..a89bdbe00184 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -489,9 +489,8 @@ static ssize_t docked_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dock_station *dock_station = dev->platform_data; - struct acpi_device *adev = NULL; + struct acpi_device *adev = acpi_fetch_acpi_dev(dock_station->handle); - acpi_bus_get_device(dock_station->handle, &adev); return sysfs_emit(buf, "%u\n", acpi_device_enumerated(adev)); } static DEVICE_ATTR_RO(docked); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index cb7b900d9466..d54fb8e54671 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -606,12 +606,10 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, int *polarity, char **name) { - int result; - struct acpi_device *device; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_pci_link *link; - result = acpi_bus_get_device(handle, &device); - if (result) { + if (!device) { acpi_handle_err(handle, "Invalid link device\n"); return -1; } @@ -658,12 +656,10 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, */ int acpi_pci_link_free_irq(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_pci_link *link; - acpi_status result; - result = acpi_bus_get_device(handle, &device); - if (result) { + if (!device) { acpi_handle_err(handle, "Invalid link device\n"); return -1; } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index b0f19f3fc798..b76db99cced3 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -67,11 +67,10 @@ static struct acpi_scan_handler pci_root_handler = { */ int acpi_is_root_bridge(acpi_handle handle) { + struct acpi_device *device = acpi_fetch_acpi_dev(handle); int ret; - struct acpi_device *device; - ret = acpi_bus_get_device(handle, &device); - if (ret) + if (!device) return 0; ret = acpi_match_device_ids(device, root_device_ids); @@ -215,11 +214,10 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) { + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_pci_root *root; - struct acpi_device *device; - if (acpi_bus_get_device(handle, &device) || - acpi_match_device_ids(device, root_device_ids)) + if (!device || acpi_match_device_ids(device, root_device_ids)) return NULL; root = acpi_driver_data(device); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5dcb02ededbc..8c4a73a1351e 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -81,9 +81,9 @@ struct acpi_power_resource *to_power_resource(struct acpi_device *device) static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - if (acpi_bus_get_device(handle, &device)) + if (!device) return NULL; return to_power_resource(device); @@ -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; @@ -916,15 +928,14 @@ static void acpi_power_add_resource_to_list(struct acpi_power_resource *resource struct acpi_device *acpi_add_power_resource(acpi_handle handle) { + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_power_resource *resource; - struct acpi_device *device = NULL; union acpi_object acpi_object; struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object }; acpi_status status; u8 state_dummy; int result; - acpi_bus_get_device(handle, &device); if (device) return device; diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 77541f939be3..368a9edefd0c 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -98,8 +98,13 @@ static int acpi_soft_cpu_online(unsigned int cpu) struct acpi_processor *pr = per_cpu(processors, cpu); struct acpi_device *device; - if (!pr || acpi_bus_get_device(pr->handle, &device)) + if (!pr) + return 0; + + device = acpi_fetch_acpi_dev(pr->handle); + if (!device) return 0; + /* * CPU got physically hotplugged and onlined for the first time: * Initialize missing things. @@ -125,9 +130,8 @@ static int acpi_soft_cpu_online(unsigned int cpu) static int acpi_soft_cpu_dead(unsigned int cpu) { struct acpi_processor *pr = per_cpu(processors, cpu); - struct acpi_device *device; - if (!pr || acpi_bus_get_device(pr->handle, &device)) + if (!pr || !acpi_fetch_acpi_dev(pr->handle)) return 0; acpi_processor_reevaluate_tstate(pr, true); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 76ef1bcc8848..ef17b95e5f37 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1101,7 +1101,7 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr) status = acpi_get_parent(handle, &pr_ahandle); while (ACPI_SUCCESS(status)) { - acpi_bus_get_device(pr_ahandle, &d); + d = acpi_fetch_acpi_dev(pr_ahandle); handle = pr_ahandle; if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID)) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 2366f54d8e9c..d0986bda2964 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -687,9 +687,9 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, if (index) return -EINVAL; - ret = acpi_bus_get_device(obj->reference.handle, &device); - if (ret) - return ret == -ENODEV ? -EINVAL : ret; + device = acpi_fetch_acpi_dev(obj->reference.handle); + if (!device) + return -EINVAL; args->fwnode = acpi_fwnode_handle(device); args->nargs = 0; @@ -719,9 +719,8 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, if (element->type == ACPI_TYPE_LOCAL_REFERENCE) { struct fwnode_handle *ref_fwnode; - ret = acpi_bus_get_device(element->reference.handle, - &device); - if (ret) + device = acpi_fetch_acpi_dev(element->reference.handle); + if (!device) return -EINVAL; nargs = 0; diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3c25ce8c95ba..c2d494784425 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -791,9 +791,9 @@ static acpi_status acpi_res_consumer_cb(acpi_handle handle, u32 depth, { struct resource *res = context; struct acpi_device **consumer = (struct acpi_device **) ret; - struct acpi_device *adev; + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); - if (acpi_bus_get_device(handle, &adev)) + if (!adev) return AE_OK; if (acpi_dev_consumes_res(adev, res)) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2c80765670bc..4dd3a9efcd0f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -135,12 +135,12 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, void **ret_p) { - struct acpi_device *device = NULL; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; bool second_pass = (bool)data; acpi_status status = AE_OK; - if (acpi_bus_get_device(handle, &device)) + if (!device) return AE_OK; if (device->handler && !device->handler->hotplug.enabled) { @@ -180,10 +180,10 @@ static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, void **ret_p) { - struct acpi_device *device = NULL; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; - if (acpi_bus_get_device(handle, &device)) + if (!device) return AE_OK; mutex_lock(&device->physical_node_lock); @@ -599,6 +599,19 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) } EXPORT_SYMBOL(acpi_bus_get_device); +/** + * acpi_fetch_acpi_dev - Retrieve ACPI device object. + * @handle: ACPI handle associated with the requested ACPI device object. + * + * Return a pointer to the ACPI device object associated with @handle, if + * present, or NULL otherwise. + */ +struct acpi_device *acpi_fetch_acpi_dev(acpi_handle handle) +{ + return handle_to_device(handle, NULL); +} +EXPORT_SYMBOL_GPL(acpi_fetch_acpi_dev); + static void get_acpi_device(void *dev) { acpi_dev_get(dev); @@ -799,7 +812,7 @@ static const char * const acpi_ignore_dep_ids[] = { static struct acpi_device *acpi_bus_get_parent(acpi_handle handle) { - struct acpi_device *device = NULL; + struct acpi_device *device; acpi_status status; /* @@ -814,7 +827,9 @@ static struct acpi_device *acpi_bus_get_parent(acpi_handle handle) status = acpi_get_parent(handle, &handle); if (ACPI_FAILURE(status)) return status == AE_NULL_ENTRY ? NULL : acpi_root; - } while (acpi_bus_get_device(handle, &device)); + + device = acpi_fetch_acpi_dev(handle); + } while (!device); return device; } @@ -1340,11 +1355,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, if (info->valid & ACPI_VALID_HID) { acpi_add_id(pnp, info->hardware_id.string); pnp->type.platform_id = 1; - } - if (info->valid & ACPI_VALID_CID) { - cid_list = &info->compatible_id_list; - for (i = 0; i < cid_list->count; i++) - acpi_add_id(pnp, cid_list->ids[i].string); + if (info->valid & ACPI_VALID_CID) { + cid_list = &info->compatible_id_list; + for (i = 0; i < cid_list->count; i++) + acpi_add_id(pnp, cid_list->ids[i].string); + } } if (info->valid & ACPI_VALID_ADR) { pnp->bus_address = info->address; @@ -1695,6 +1710,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) { struct list_head resource_list; bool is_serial_bus_slave = false; + static const struct acpi_device_id ignore_serial_bus_ids[] = { /* * These devices have multiple I2cSerialBus resources and an i2c-client * must be instantiated for each, each with its own i2c_device_id. @@ -1703,11 +1719,18 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) * drivers/platform/x86/i2c-multi-instantiate.c driver, which knows * which i2c_device_id to use for each resource. */ - static const struct acpi_device_id i2c_multi_instantiate_ids[] = { {"BSG1160", }, {"BSG2150", }, {"INT33FE", }, {"INT3515", }, + /* + * HIDs of device with an UartSerialBusV2 resource for which userspace + * expects a regular tty cdev to be created (instead of the in kernel + * serdev) and which have a kernel driver which expects a platform_dev + * such as the rfkill-gpio driver. + */ + {"BCM4752", }, + {"LNV4752", }, {} }; @@ -1721,8 +1744,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) fwnode_property_present(&device->fwnode, "baud"))) return true; - /* Instantiate a pdev for the i2c-multi-instantiate drv to bind to */ - if (!acpi_match_device_ids(device, i2c_multi_instantiate_ids)) + if (!acpi_match_device_ids(device, ignore_serial_bus_ids)) return false; INIT_LIST_HEAD(&resource_list); @@ -2003,11 +2025,10 @@ static bool acpi_bus_scan_second_pass; static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, struct acpi_device **adev_p) { - struct acpi_device *device = NULL; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); acpi_object_type acpi_type; int type; - acpi_bus_get_device(handle, &device); if (device) goto out; @@ -2548,8 +2569,8 @@ int __init acpi_scan_init(void) if (result) goto out; - result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root); - if (result) + acpi_root = acpi_fetch_acpi_dev(ACPI_ROOT_OBJECT); + if (!acpi_root) goto out; /* Fixed feature devices do not exist on HW-reduced platform */ 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++; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 95105db642b9..75cda1315235 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -697,7 +697,6 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, struct acpi_device *device = cdev->devdata; struct acpi_thermal *tz = thermal->devdata; struct acpi_device *dev; - acpi_status status; acpi_handle handle; int i; int j; @@ -715,8 +714,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, for (i = 0; i < tz->trips.passive.devices.count; i++) { handle = tz->trips.passive.devices.handles[i]; - status = acpi_bus_get_device(handle, &dev); - if (ACPI_FAILURE(status) || dev != device) + dev = acpi_fetch_acpi_dev(handle); + if (dev != device) continue; if (bind) result = @@ -741,8 +740,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, j < tz->trips.active[i].devices.count; j++) { handle = tz->trips.active[i].devices.handles[j]; - status = acpi_bus_get_device(handle, &dev); - if (ACPI_FAILURE(status) || dev != device) + dev = acpi_fetch_acpi_dev(handle); + if (dev != device) continue; if (bind) result = thermal_zone_bind_cooling_device diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 068e393ea0c6..4f64713e9917 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -59,18 +59,16 @@ static void acpi_video_parse_cmdline(void) static acpi_status find_video(acpi_handle handle, u32 lvl, void *context, void **rv) { + struct acpi_device *acpi_dev = acpi_fetch_acpi_dev(handle); long *cap = context; struct pci_dev *dev; - struct acpi_device *acpi_dev; static const struct acpi_device_id video_ids[] = { {ACPI_VIDEO_HID, 0}, {"", 0}, }; - if (acpi_bus_get_device(handle, &acpi_dev)) - return AE_OK; - if (!acpi_match_device_ids(acpi_dev, video_ids)) { + if (acpi_dev && !acpi_match_device_ids(acpi_dev, video_ids)) { dev = acpi_get_pci_dev(handle); if (!dev) return AE_OK; diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 1c48358b43ba..abc06e7f89d8 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -293,9 +293,9 @@ static void lpi_check_constraints(void) for (i = 0; i < lpi_constraints_table_size; ++i) { acpi_handle handle = lpi_constraints_table[i].handle; - struct acpi_device *adev; + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); - if (!handle || acpi_bus_get_device(handle, &adev)) + if (!adev) continue; acpi_handle_debug(handle, diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index f22f23933063..ef9ee8bbe4e6 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -10,6 +10,7 @@ #include <linux/acpi.h> #include <linux/dmi.h> +#include <linux/platform_device.h> #include <asm/cpu_device_id.h> #include <asm/intel-family.h> #include "../internal.h" @@ -160,3 +161,113 @@ bool force_storage_d3(void) { return x86_match_cpu(storage_d3_cpu_ids); } + +#if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS) +/* + * x86 ACPI boards which ship with only Android as their factory image usually + * declare a whole bunch of bogus I2C devices in their ACPI tables and sometimes + * there are issues with serdev devices on these boards too, e.g. the resource + * points to the wrong serdev_controller. + * + * Instantiating I2C / serdev devs for these bogus devs causes various issues, + * e.g. GPIO/IRQ resource conflicts because sometimes drivers do bind to them. + * The Android x86 kernel fork shipped on these devices has some special code + * to remove the bogus I2C clients (and AFAICT serdevs are ignored completely). + * + * The acpi_quirk_skip_*_enumeration() functions below are used by the I2C or + * serdev code to skip instantiating any I2C or serdev devs on broken boards. + * + * In case of I2C an exception is made for HIDs on the i2c_acpi_known_good_ids + * list. These are known to always be correct (and in case of the audio-codecs + * the drivers heavily rely on the codec being enumerated through ACPI). + * + * Note these boards typically do actually have I2C and serdev devices, + * just different ones then the ones described in their DSDT. The devices + * which are actually present are manually instantiated by the + * drivers/platform/x86/x86-android-tablets.c kernel module. + */ +#define ACPI_QUIRK_SKIP_I2C_CLIENTS BIT(0) +#define ACPI_QUIRK_UART1_TTY_UART2_SKIP BIT(1) + +static const struct dmi_system_id acpi_skip_serial_bus_enumeration_ids[] = { + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), + }, + .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | + ACPI_QUIRK_UART1_TTY_UART2_SKIP), + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), + }, + .driver_data = (void *)ACPI_QUIRK_SKIP_I2C_CLIENTS, + }, + { + /* Whitelabel (sold as various brands) TM800A550L */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS version */ + DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"), + }, + .driver_data = (void *)ACPI_QUIRK_SKIP_I2C_CLIENTS, + }, + {} +}; + +static const struct acpi_device_id i2c_acpi_known_good_ids[] = { + { "10EC5640", 0 }, /* RealTek ALC5640 audio codec */ + { "INT33F4", 0 }, /* X-Powers AXP288 PMIC */ + { "INT33FD", 0 }, /* Intel Crystal Cove PMIC */ + { "NPCE69A", 0 }, /* Asus Transformer keyboard dock */ + {} +}; + +bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev) +{ + const struct dmi_system_id *dmi_id; + long quirks; + + dmi_id = dmi_first_match(acpi_skip_serial_bus_enumeration_ids); + if (!dmi_id) + return false; + + quirks = (unsigned long)dmi_id->driver_data; + if (!(quirks & ACPI_QUIRK_SKIP_I2C_CLIENTS)) + return false; + + return acpi_match_device_ids(adev, i2c_acpi_known_good_ids); +} +EXPORT_SYMBOL_GPL(acpi_quirk_skip_i2c_client_enumeration); + +int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) +{ + struct acpi_device *adev = ACPI_COMPANION(controller_parent); + const struct dmi_system_id *dmi_id; + long quirks = 0; + + *skip = false; + + /* !dev_is_platform() to not match on PNP enumerated debug UARTs */ + if (!adev || !adev->pnp.unique_id || !dev_is_platform(controller_parent)) + return 0; + + dmi_id = dmi_first_match(acpi_skip_serial_bus_enumeration_ids); + if (dmi_id) + quirks = (unsigned long)dmi_id->driver_data; + + if (quirks & ACPI_QUIRK_UART1_TTY_UART2_SKIP) { + if (!strcmp(adev->pnp.unique_id, "1")) + return -ENODEV; /* Create tty cdev instead of serdev */ + + if (!strcmp(adev->pnp.unique_id, "2")) + *skip = true; + } + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration); +#endif diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 92c1cc07ed46..15332baa9e85 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -254,6 +254,13 @@ static void i2c_acpi_register_device(struct i2c_adapter *adapter, struct acpi_device *adev, struct i2c_board_info *info) { + /* + * Skip registration on boards where the ACPI tables are + * known to contain bogus I2C devices. + */ + if (acpi_quirk_skip_i2c_client_enumeration(adev)) + return; + adev->power.flags.ignore_parent = true; acpi_device_set_enumerated(adev); diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index f1324fe99378..92e3433276f8 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -727,10 +727,24 @@ static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, static int acpi_serdev_register_devices(struct serdev_controller *ctrl) { acpi_status status; + bool skip; + int ret; if (!has_acpi_companion(ctrl->dev.parent)) return -ENODEV; + /* + * Skip registration on boards where the ACPI tables are known to + * contain buggy devices. Note serdev_controller_add() must still + * succeed in this case, so that the proper serdev devices can be + * added "manually" later. + */ + ret = acpi_quirk_skip_serdev_enumeration(ctrl->dev.parent, &skip); + if (ret) + return ret; + if (skip) + return 0; + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, SERDEV_ACPI_MAX_SCAN_DEPTH, acpi_serdev_add_device, NULL, ctrl, NULL); |