summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-06-02 23:25:52 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2020-06-02 23:25:52 +0300
commit118d6e98293b30aee378a6b08d27a35320a3e34f (patch)
treef96ba1dd4e7f6ae7759061e7728f8dc705f73c67
parent355ba37d756c38962fe9bb616f5f48eb12a7e11e (diff)
parent48ccdeddc54771ecdc46fac098bac689e9df24ca (diff)
downloadlinux-118d6e98293b30aee378a6b08d27a35320a3e34f.tar.xz
Merge tag 'acpi-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI updates from Rafael Wysocki: "These update the ACPICA code in the kernel to upstream revision 20200430, fix several reference counting errors related to ACPI tables, add _Exx / _Lxx support to the GED driver, add a new acpi_evaluate_reg() helper, add new DPTF battery participant driver and extend the DPFT power participant driver, improve the handling of memory failures in the APEI code, add a blacklist entry to the backlight driver, update the PMIC driver and the processor idle driver, fix two kobject reference count leaks, and make a few janitory changes. Specifics: - Update the ACPICA code in the kernel to upstream revision 20200430: - Move acpi_gbl_next_cmd_num definition (Erik Kaneda). - Ignore AE_ALREADY_EXISTS status in the disassembler when parsing create operators (Erik Kaneda). - Add status checks to the dispatcher (Erik Kaneda). - Fix required parameters for _NIG and _NIH (Erik Kaneda). - Make acpi_protocol_lengths static (Yue Haibing). - Fix ACPI table reference counting errors in several places, mostly in error code paths (Hanjun Guo). - Extend the Generic Event Device (GED) driver to support _Exx and _Lxx handler methods (Ard Biesheuvel). - Add new acpi_evaluate_reg() helper and modify the ACPI PCI hotplug code to use it (Hans de Goede). - Add new DPTF battery participant driver and make the DPFT power participant driver create more sysfs device attributes (Srinivas Pandruvada). - Improve the handling of memory failures in APEI (James Morse). - Add new blacklist entry for Acer TravelMate 5735Z to the backlight driver (Paul Menzel). - Add i2c address for thermal control to the PMIC driver (Mauro Carvalho Chehab). - Allow the ACPI processor idle driver to work on platforms with only one ACPI C-state present (Zhang Rui). - Fix kobject reference count leaks in error code paths in two places (Qiushi Wu). - Delete unused proc filename macros and make some symbols static (Pascal Terjan, Zheng Zengkai, Zou Wei)" * tag 'acpi-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (32 commits) ACPI: CPPC: Fix reference count leak in acpi_cppc_processor_probe() ACPI: sysfs: Fix reference count leak in acpi_sysfs_add_hotplug_profile() ACPI: GED: use correct trigger type field in _Exx / _Lxx handling ACPI: DPTF: Add battery participant driver ACPI: DPTF: Additional sysfs attributes for power participant driver ACPI: video: Use native backlight on Acer TravelMate 5735Z arm64: acpi: Make apei_claim_sea() synchronise with APEI's irq work ACPI: APEI: Kick the memory_failure() queue for synchronous errors mm/memory-failure: Add memory_failure_queue_kick() ACPI / PMIC: Add i2c address for thermal control ACPI: GED: add support for _Exx / _Lxx handler methods ACPI: Delete unused proc filename macros ACPI: hotplug: PCI: Use the new acpi_evaluate_reg() helper ACPI: utils: Add acpi_evaluate_reg() helper ACPI: debug: Make two functions static ACPI: sleep: Put the FACS table after using it ACPI: scan: Put SPCR and STAO table after using it ACPI: EC: Put the ACPI table after using it ACPI: APEI: Put the HEST table for error path ACPI: APEI: Put the error record serialization table for error path ...
-rw-r--r--Documentation/ABI/testing/sysfs-platform-dptf62
-rw-r--r--arch/arm64/kernel/acpi.c25
-rw-r--r--arch/arm64/mm/fault.c12
-rw-r--r--drivers/acpi/acpi_dbg.c4
-rw-r--r--drivers/acpi/acpi_lpit.c3
-rw-r--r--drivers/acpi/acpi_watchdog.c7
-rw-r--r--drivers/acpi/acpica/acglobal.h1
-rw-r--r--drivers/acpi/acpica/acpredef.h4
-rw-r--r--drivers/acpi/acpica/dbhistry.c1
-rw-r--r--drivers/acpi/acpica/dsfield.c22
-rw-r--r--drivers/acpi/acpica/exfield.c2
-rw-r--r--drivers/acpi/apei/bert.c6
-rw-r--r--drivers/acpi/apei/einj.c5
-rw-r--r--drivers/acpi/apei/erst.c4
-rw-r--r--drivers/acpi/apei/ghes.c67
-rw-r--r--drivers/acpi/apei/hest.c5
-rw-r--r--drivers/acpi/button.c1
-rw-r--r--drivers/acpi/cppc_acpi.c5
-rw-r--r--drivers/acpi/dptf/dptf_power.c147
-rw-r--r--drivers/acpi/ec.c21
-rw-r--r--drivers/acpi/evged.c22
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/pmic/intel_pmic_chtdc_ti.c1
-rw-r--r--drivers/acpi/power.c2
-rw-r--r--drivers/acpi/processor_idle.c9
-rw-r--r--drivers/acpi/sbs.c3
-rw-r--r--drivers/acpi/scan.c15
-rw-r--r--drivers/acpi/sleep.c4
-rw-r--r--drivers/acpi/sysfs.c4
-rw-r--r--drivers/acpi/utils.c25
-rw-r--r--drivers/acpi/video_detect.c10
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c13
-rw-r--r--include/acpi/acpi_bus.h1
-rw-r--r--include/acpi/acpixf.h2
-rw-r--r--include/acpi/ghes.h3
-rw-r--r--include/linux/mm.h1
-rw-r--r--mm/memory-failure.c15
37 files changed, 438 insertions, 98 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-dptf b/Documentation/ABI/testing/sysfs-platform-dptf
index 325dc0667dbb..eeed81ca6949 100644
--- a/Documentation/ABI/testing/sysfs-platform-dptf
+++ b/Documentation/ABI/testing/sysfs-platform-dptf
@@ -27,10 +27,12 @@ KernelVersion: v4.10
Contact: linux-acpi@vger.kernel.org
Description:
(RO) Display the platform power source
- 0x00 = DC
- 0x01 = AC
- 0x02 = USB
- 0x03 = Wireless Charger
+ bits[3:0] Current power source
+ 0x00 = DC
+ 0x01 = AC
+ 0x02 = USB
+ 0x03 = Wireless Charger
+ bits[7:4] Power source sequence number
What: /sys/bus/platform/devices/INT3407:00/dptf_power/battery_steady_power
Date: Jul, 2016
@@ -38,3 +40,55 @@ KernelVersion: v4.10
Contact: linux-acpi@vger.kernel.org
Description:
(RO) The maximum sustained power for battery in milliwatts.
+
+What: /sys/bus/platform/devices/INT3407:00/dptf_power/rest_of_platform_power_mw
+Date: June, 2020
+KernelVersion: v5.8
+Contact: linux-acpi@vger.kernel.org
+Description:
+ (RO) Shows the rest (outside of SoC) of worst-case platform power.
+
+What: /sys/bus/platform/devices/INT3407:00/dptf_power/prochot_confirm
+Date: June, 2020
+KernelVersion: v5.8
+Contact: linux-acpi@vger.kernel.org
+Description:
+ (WO) Confirm embedded controller about a prochot notification.
+
+What: /sys/bus/platform/devices/INT3532:00/dptf_battery/max_platform_power_mw
+Date: June, 2020
+KernelVersion: v5.8
+Contact: linux-acpi@vger.kernel.org
+Description:
+ (RO) The maximum platform power that can be supported by the battery in milli watts.
+
+What: /sys/bus/platform/devices/INT3532:00/dptf_battery/max_steady_state_power_mw
+Date: June, 2020
+KernelVersion: v5.8
+Contact: linux-acpi@vger.kernel.org
+Description:
+ (RO) The maximum sustained power for battery in milli watts.
+
+What: /sys/bus/platform/devices/INT3532:00/dptf_battery/high_freq_impedance_mohm
+Date: June, 2020
+KernelVersion: v5.8
+Contact: linux-acpi@vger.kernel.org
+Description:
+ (RO) The high frequency impedance value that can be obtained from battery
+ fuel gauge in milli Ohms.
+
+What: /sys/bus/platform/devices/INT3532:00/dptf_battery/no_load_voltage_mv
+Date: June, 2020
+KernelVersion: v5.8
+Contact: linux-acpi@vger.kernel.org
+Description:
+ (RO) The no-load voltage that can be obtained from battery fuel gauge in
+ milli volts.
+
+What: /sys/bus/platform/devices/INT3532:00/dptf_battery/current_discharge_capbility_ma
+Date: June, 2020
+KernelVersion: v5.8
+Contact: linux-acpi@vger.kernel.org
+Description:
+ (RO) The battery discharge current capability obtained from battery fuel gauge in
+ milli Amps.
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index a100483b47c4..46ec402e97ed 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/irq_work.h>
#include <linux/memblock.h>
#include <linux/of_fdt.h>
#include <linux/smp.h>
@@ -269,6 +270,7 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
int apei_claim_sea(struct pt_regs *regs)
{
int err = -ENOENT;
+ bool return_to_irqs_enabled;
unsigned long current_flags;
if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
@@ -276,6 +278,12 @@ int apei_claim_sea(struct pt_regs *regs)
current_flags = local_daif_save_flags();
+ /* current_flags isn't useful here as daif doesn't tell us about pNMI */
+ return_to_irqs_enabled = !irqs_disabled_flags(arch_local_save_flags());
+
+ if (regs)
+ return_to_irqs_enabled = interrupts_enabled(regs);
+
/*
* SEA can interrupt SError, mask it and describe this as an NMI so
* that APEI defers the handling.
@@ -284,6 +292,23 @@ int apei_claim_sea(struct pt_regs *regs)
nmi_enter();
err = ghes_notify_sea();
nmi_exit();
+
+ /*
+ * APEI NMI-like notifications are deferred to irq_work. Unless
+ * we interrupted irqs-masked code, we can do that now.
+ */
+ if (!err) {
+ if (return_to_irqs_enabled) {
+ local_daif_restore(DAIF_PROCCTX_NOIRQ);
+ __irq_enter();
+ irq_work_run();
+ __irq_exit();
+ } else {
+ pr_warn_ratelimited("APEI work queued but not completed");
+ err = -EINPROGRESS;
+ }
+ }
+
local_daif_restore(current_flags);
return err;
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index c9cedc0432d2..dff2d72b0883 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -635,11 +635,13 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
inf = esr_to_fault_info(esr);
- /*
- * Return value ignored as we rely on signal merging.
- * Future patches will make this more robust.
- */
- apei_claim_sea(regs);
+ if (user_mode(regs) && apei_claim_sea(regs) == 0) {
+ /*
+ * APEI claimed this as a firmware-first notification.
+ * Some processing deferred to task_work before ret_to_user().
+ */
+ return 0;
+ }
if (esr & ESR_ELx_FnV)
siaddr = NULL;
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index 7a265c2171c0..6041974c7627 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -745,7 +745,7 @@ static const struct acpi_debugger_ops acpi_aml_debugger = {
.notify_command_complete = acpi_aml_notify_command_complete,
};
-int __init acpi_aml_init(void)
+static int __init acpi_aml_init(void)
{
int ret;
@@ -771,7 +771,7 @@ int __init acpi_aml_init(void)
return 0;
}
-void __exit acpi_aml_exit(void)
+static void __exit acpi_aml_exit(void)
{
if (acpi_aml_initialized) {
acpi_unregister_debugger(&acpi_aml_debugger);
diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c
index 953437a216f6..48e5059d67ca 100644
--- a/drivers/acpi/acpi_lpit.c
+++ b/drivers/acpi/acpi_lpit.c
@@ -151,10 +151,11 @@ void acpi_init_lpit(void)
struct acpi_table_lpit *lpit;
status = acpi_get_table(ACPI_SIG_LPIT, 0, (struct acpi_table_header **)&lpit);
-
if (ACPI_FAILURE(status))
return;
lpit_process((u64)lpit + sizeof(*lpit),
(u64)lpit + lpit->header.length);
+
+ acpi_put_table((struct acpi_table_header *)lpit);
}
diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c
index 6e9ec6e3fe47..5c1e9ea43123 100644
--- a/drivers/acpi/acpi_watchdog.c
+++ b/drivers/acpi/acpi_watchdog.c
@@ -73,6 +73,7 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void)
}
if (acpi_watchdog_uses_rtc(wdat)) {
+ acpi_put_table((struct acpi_table_header *)wdat);
pr_info("Skipping WDAT on this system because it uses RTC SRAM\n");
return NULL;
}
@@ -117,12 +118,12 @@ void __init acpi_watchdog_init(void)
/* Watchdog disabled by BIOS */
if (!(wdat->flags & ACPI_WDAT_ENABLED))
- return;
+ goto fail_put_wdat;
/* Skip legacy PCI WDT devices */
if (wdat->pci_segment != 0xff || wdat->pci_bus != 0xff ||
wdat->pci_device != 0xff || wdat->pci_function != 0xff)
- return;
+ goto fail_put_wdat;
INIT_LIST_HEAD(&resource_list);
@@ -188,4 +189,6 @@ void __init acpi_watchdog_init(void)
fail_free_resource_list:
resource_list_free(&resource_list);
+fail_put_wdat:
+ acpi_put_table((struct acpi_table_header *)wdat);
}
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 38ffa2c0a496..1030a0ce1599 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -290,6 +290,7 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
#ifdef ACPI_DEBUGGER
ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID);
+ACPI_INIT_GLOBAL(u32, acpi_gbl_next_cmd_num, 1);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_ini_methods);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support);
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index cd0f5df0ea23..2cbb56652f1c 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -640,10 +640,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_NIC", METHOD_0ARGS, /* ACPI 6.3 */
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
- {{"_NIG", METHOD_1ARGS(ACPI_TYPE_BUFFER), /* ACPI 6.3 */
+ {{"_NIG", METHOD_0ARGS, /* ACPI 6.3 */
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
- {{"_NIH", METHOD_0ARGS, /* ACPI 6.3 */
+ {{"_NIH", METHOD_1ARGS(ACPI_TYPE_BUFFER), /* ACPI 6.3 */
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
{{"_NTT", METHOD_0ARGS,
diff --git a/drivers/acpi/acpica/dbhistry.c b/drivers/acpi/acpica/dbhistry.c
index bb9600b867ee..f5fba14461a6 100644
--- a/drivers/acpi/acpica/dbhistry.c
+++ b/drivers/acpi/acpica/dbhistry.c
@@ -27,7 +27,6 @@ static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE];
static u16 acpi_gbl_lo_history = 0;
static u16 acpi_gbl_num_history = 0;
static u16 acpi_gbl_next_history_index = 0;
-u32 acpi_gbl_next_cmd_num = 1;
/*******************************************************************************
*
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index c901f5aec739..fa768b3a989e 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -177,7 +177,10 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
arg->common.value.string, ACPI_TYPE_ANY,
ACPI_IMODE_LOAD_PASS1, flags,
walk_state, &node);
- if (ACPI_FAILURE(status)) {
+ if ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE)
+ && status == AE_ALREADY_EXISTS) {
+ status = AE_OK;
+ } else if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE(walk_state->scope_info,
arg->common.value.string, status);
return_ACPI_STATUS(status);
@@ -514,13 +517,20 @@ acpi_ds_create_field(union acpi_parse_object *op,
info.region_node = region_node;
status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
if (info.region_node->object->region.space_id ==
- ACPI_ADR_SPACE_PLATFORM_COMM
- && !(region_node->object->field.internal_pcc_buffer =
- ACPI_ALLOCATE_ZEROED(info.region_node->object->region.
- length))) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ ACPI_ADR_SPACE_PLATFORM_COMM) {
+ region_node->object->field.internal_pcc_buffer =
+ ACPI_ALLOCATE_ZEROED(info.region_node->object->region.
+ length);
+ if (!region_node->object->field.internal_pcc_buffer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
}
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index e85eb31e5075..3323a2ba6a31 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -22,7 +22,7 @@ ACPI_MODULE_NAME("exfield")
*/
#define ACPI_INVALID_PROTOCOL_ID 0x80
#define ACPI_MAX_PROTOCOL_ID 0x0F
-const u8 acpi_protocol_lengths[] = {
+static const u8 acpi_protocol_lengths[] = {
ACPI_INVALID_PROTOCOL_ID, /* 0 - reserved */
ACPI_INVALID_PROTOCOL_ID, /* 1 - reserved */
0x00, /* 2 - ATTRIB_QUICK */
diff --git a/drivers/acpi/apei/bert.c b/drivers/acpi/apei/bert.c
index 1155fb9dcc3a..19e50fcbf4d6 100644
--- a/drivers/acpi/apei/bert.c
+++ b/drivers/acpi/apei/bert.c
@@ -119,7 +119,7 @@ static int __init bert_init(void)
rc = bert_check_table(bert_tab);
if (rc) {
pr_err(FW_BUG "table invalid.\n");
- return rc;
+ goto out_put_bert_tab;
}
region_len = bert_tab->region_length;
@@ -127,7 +127,7 @@ static int __init bert_init(void)
rc = apei_resources_add(&bert_resources, bert_tab->address,
region_len, true);
if (rc)
- return rc;
+ goto out_put_bert_tab;
rc = apei_resources_request(&bert_resources, "APEI BERT");
if (rc)
goto out_fini;
@@ -142,6 +142,8 @@ static int __init bert_init(void)
apei_resources_release(&bert_resources);
out_fini:
apei_resources_fini(&bert_resources);
+out_put_bert_tab:
+ acpi_put_table((struct acpi_table_header *)bert_tab);
return rc;
}
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 086373f8ccb1..133156759551 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -692,7 +692,7 @@ static int __init einj_init(void)
rc = einj_check_table(einj_tab);
if (rc) {
pr_warn(FW_BUG "Invalid EINJ table.\n");
- return -EINVAL;
+ goto err_put_table;
}
rc = -ENOMEM;
@@ -760,6 +760,8 @@ err_release:
err_fini:
apei_resources_fini(&einj_resources);
debugfs_remove_recursive(einj_debug_dir);
+err_put_table:
+ acpi_put_table((struct acpi_table_header *)einj_tab);
return rc;
}
@@ -780,6 +782,7 @@ static void __exit einj_exit(void)
apei_resources_release(&einj_resources);
apei_resources_fini(&einj_resources);
debugfs_remove_recursive(einj_debug_dir);
+ acpi_put_table((struct acpi_table_header *)einj_tab);
}
module_init(einj_init);
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 2015a0967cbb..2e0b0fcad960 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -1122,7 +1122,7 @@ static int __init erst_init(void)
rc = erst_check_table(erst_tab);
if (rc) {
pr_err(FW_BUG "ERST table is invalid.\n");
- goto err;
+ goto err_put_erst_tab;
}
apei_resources_init(&erst_resources);
@@ -1196,6 +1196,8 @@ err_release:
apei_resources_release(&erst_resources);
err_fini:
apei_resources_fini(&erst_resources);
+err_put_erst_tab:
+ acpi_put_table((struct acpi_table_header *)erst_tab);
err:
erst_disable = 1;
return rc;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index aabe9c5ee515..81bf71b10d44 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -40,6 +40,7 @@
#include <linux/sched/clock.h>
#include <linux/uuid.h>
#include <linux/ras.h>
+#include <linux/task_work.h>
#include <acpi/actbl1.h>
#include <acpi/ghes.h>
@@ -408,23 +409,46 @@ static void ghes_clear_estatus(struct ghes *ghes,
ghes_ack_error(ghes->generic_v2);
}
-static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev)
+/*
+ * Called as task_work before returning to user-space.
+ * Ensure any queued work has been done before we return to the context that
+ * triggered the notification.
+ */
+static void ghes_kick_task_work(struct callback_head *head)
+{
+ struct acpi_hest_generic_status *estatus;
+ struct ghes_estatus_node *estatus_node;
+ u32 node_len;
+
+ estatus_node = container_of(head, struct ghes_estatus_node, task_work);
+ if (IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
+ memory_failure_queue_kick(estatus_node->task_work_cpu);
+
+ estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
+ node_len = GHES_ESTATUS_NODE_LEN(cper_estatus_len(estatus));
+ gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node, node_len);
+}
+
+static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
+ int sev)
{
-#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
unsigned long pfn;
int flags = -1;
int sec_sev = ghes_severity(gdata->error_severity);
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
+ if (!IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
+ return false;
+
if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
- return;
+ return false;
pfn = mem_err->physical_addr >> PAGE_SHIFT;
if (!pfn_valid(pfn)) {
pr_warn_ratelimited(FW_WARN GHES_PFX
"Invalid address in generic error data: %#llx\n",
mem_err->physical_addr);
- return;
+ return false;
}
/* iff following two events can be handled properly by now */
@@ -434,9 +458,12 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int
if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
flags = 0;
- if (flags != -1)
+ if (flags != -1) {
memory_failure_queue(pfn, flags);
-#endif
+ return true;
+ }
+
+ return false;
}
/*
@@ -484,7 +511,7 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
#endif
}
-static void ghes_do_proc(struct ghes *ghes,
+static bool ghes_do_proc(struct ghes *ghes,
const struct acpi_hest_generic_status *estatus)
{
int sev, sec_sev;
@@ -492,6 +519,7 @@ static void ghes_do_proc(struct ghes *ghes,
guid_t *sec_type;
const guid_t *fru_id = &guid_null;
char *fru_text = "";
+ bool queued = false;
sev = ghes_severity(estatus->error_severity);
apei_estatus_for_each_section(estatus, gdata) {
@@ -509,7 +537,7 @@ static void ghes_do_proc(struct ghes *ghes,
ghes_edac_report_mem_error(sev, mem_err);
arch_apei_report_mem_error(sev, mem_err);
- ghes_handle_memory_failure(gdata, sev);
+ queued = ghes_handle_memory_failure(gdata, sev);
}
else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
ghes_handle_aer(gdata);
@@ -526,6 +554,8 @@ static void ghes_do_proc(struct ghes *ghes,
gdata->error_data_length);
}
}
+
+ return queued;
}
static void __ghes_print_estatus(const char *pfx,
@@ -821,7 +851,9 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
struct ghes_estatus_node *estatus_node;
struct acpi_hest_generic *generic;
struct acpi_hest_generic_status *estatus;
+ bool task_work_pending;
u32 len, node_len;
+ int ret;
llnode = llist_del_all(&ghes_estatus_llist);
/*
@@ -836,14 +868,26 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
len = cper_estatus_len(estatus);
node_len = GHES_ESTATUS_NODE_LEN(len);
- ghes_do_proc(estatus_node->ghes, estatus);
+ task_work_pending = ghes_do_proc(estatus_node->ghes, estatus);
if (!ghes_estatus_cached(estatus)) {
generic = estatus_node->generic;
if (ghes_print_estatus(NULL, generic, estatus))
ghes_estatus_cache_add(generic, estatus);
}
- gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node,
- node_len);
+
+ if (task_work_pending && current->mm != &init_mm) {
+ estatus_node->task_work.func = ghes_kick_task_work;
+ estatus_node->task_work_cpu = smp_processor_id();
+ ret = task_work_add(current, &estatus_node->task_work,
+ true);
+ if (ret)
+ estatus_node->task_work.func = NULL;
+ }
+
+ if (!estatus_node->task_work.func)
+ gen_pool_free(ghes_estatus_pool,
+ (unsigned long)estatus_node, node_len);
+
llnode = next;
}
}
@@ -903,6 +947,7 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
estatus_node->ghes = ghes;
estatus_node->generic = ghes->generic;
+ estatus_node->task_work.func = NULL;
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) {
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index 822402480f7d..953a2fae8b15 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -243,8 +243,8 @@ void __init acpi_hest_init(void)
} else if (ACPI_FAILURE(status)) {
const char *msg = acpi_format_exception(status);
pr_err(HEST_PFX "Failed to get table, %s\n", msg);
- rc = -EINVAL;
- goto err;
+ hest_disable = HEST_DISABLED;
+ return;
}
rc = apei_hest_parse(hest_parse_cmc, NULL);
@@ -266,4 +266,5 @@ void __init acpi_hest_init(void)
return;
err:
hest_disable = HEST_DISABLED;
+ acpi_put_table((struct acpi_table_header *)hest_tab);
}
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 78cfc70cb320..3c35e57dd854 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -24,7 +24,6 @@
#define PREFIX "ACPI: "
#define ACPI_BUTTON_CLASS "button"
-#define ACPI_BUTTON_FILE_INFO "info"
#define ACPI_BUTTON_FILE_STATE "state"
#define ACPI_BUTTON_TYPE_UNKNOWN 0x00
#define ACPI_BUTTON_NOTIFY_STATUS 0x80
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 8b2e89c20c11..7a99b19bb893 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -350,7 +350,7 @@ static void cppc_chan_tx_done(struct mbox_client *cl, void *msg, int ret)
*(u16 *)msg, ret);
}
-struct mbox_client cppc_mbox_cl = {
+static struct mbox_client cppc_mbox_cl = {
.tx_done = cppc_chan_tx_done,
.knows_txdone = true,
};
@@ -597,7 +597,7 @@ bool __weak cpc_ffh_supported(void)
*
* Return: 0 for success, errno for failure
*/
-int pcc_data_alloc(int pcc_ss_id)
+static int pcc_data_alloc(int pcc_ss_id)
{
if (pcc_ss_id < 0 || pcc_ss_id >= MAX_PCC_SUBSPACES)
return -EINVAL;
@@ -846,6 +846,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
"acpi_cppc");
if (ret) {
per_cpu(cpc_desc_ptr, pr->id) = NULL;
+ kobject_put(&cpc_ptr->kobj);
goto out_free;
}
diff --git a/drivers/acpi/dptf/dptf_power.c b/drivers/acpi/dptf/dptf_power.c
index e4e8b75d39f0..5fab7e350db8 100644
--- a/drivers/acpi/dptf/dptf_power.c
+++ b/drivers/acpi/dptf/dptf_power.c
@@ -10,12 +10,19 @@
#include <linux/platform_device.h>
/*
- * Presentation of attributes which are defined for INT3407. They are:
+ * Presentation of attributes which are defined for INT3407 and INT3532.
+ * They are:
* PMAX : Maximum platform powe
* PSRC : Platform power source
* ARTG : Adapter rating
* CTYP : Charger type
* PBSS : Battery steady power
+ * PROP : Rest of worst case platform Power
+ * PBSS : Power Battery Steady State
+ * PBSS : Power Battery Steady State
+ * RBHF : High Frequency Impedance
+ * VBNL : Instantaneous No-Load Voltage
+ * CMPP : Current Discharge Capability
*/
#define DPTF_POWER_SHOW(name, object) \
static ssize_t name##_show(struct device *dev,\
@@ -39,12 +46,42 @@ DPTF_POWER_SHOW(platform_power_source, PSRC)
DPTF_POWER_SHOW(adapter_rating_mw, ARTG)
DPTF_POWER_SHOW(battery_steady_power_mw, PBSS)
DPTF_POWER_SHOW(charger_type, CTYP)
+DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP)
+DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS)
+DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF)
+DPTF_POWER_SHOW(no_load_voltage_mv, VBNL)
+DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP);
static DEVICE_ATTR_RO(max_platform_power_mw);
static DEVICE_ATTR_RO(platform_power_source);
static DEVICE_ATTR_RO(adapter_rating_mw);
static DEVICE_ATTR_RO(battery_steady_power_mw);
static DEVICE_ATTR_RO(charger_type);
+static DEVICE_ATTR_RO(rest_of_platform_power_mw);
+static DEVICE_ATTR_RO(max_steady_state_power_mw);
+static DEVICE_ATTR_RO(high_freq_impedance_mohm);
+static DEVICE_ATTR_RO(no_load_voltage_mv);
+static DEVICE_ATTR_RO(current_discharge_capbility_ma);
+
+static ssize_t prochot_confirm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct acpi_device *acpi_dev = dev_get_drvdata(dev);
+ acpi_status status;
+ int seq_no;
+
+ if (kstrtouint(buf, 0, &seq_no) < 0)
+ return -EINVAL;
+
+ status = acpi_execute_simple_method(acpi_dev->handle, "PBOK", seq_no);
+ if (ACPI_SUCCESS(status))
+ return count;
+
+ return -EINVAL;
+}
+
+static DEVICE_ATTR_WO(prochot_confirm);
static struct attribute *dptf_power_attrs[] = {
&dev_attr_max_platform_power_mw.attr,
@@ -52,6 +89,8 @@ static struct attribute *dptf_power_attrs[] = {
&dev_attr_adapter_rating_mw.attr,
&dev_attr_battery_steady_power_mw.attr,
&dev_attr_charger_type.attr,
+ &dev_attr_rest_of_platform_power_mw.attr,
+ &dev_attr_prochot_confirm.attr,
NULL
};
@@ -60,10 +99,79 @@ static const struct attribute_group dptf_power_attribute_group = {
.name = "dptf_power"
};
+static struct attribute *dptf_battery_attrs[] = {
+ &dev_attr_max_platform_power_mw.attr,
+ &dev_attr_max_steady_state_power_mw.attr,
+ &dev_attr_high_freq_impedance_mohm.attr,
+ &dev_attr_no_load_voltage_mv.attr,
+ &dev_attr_current_discharge_capbility_ma.attr,
+ NULL
+};
+
+static const struct attribute_group dptf_battery_attribute_group = {
+ .attrs = dptf_battery_attrs,
+ .name = "dptf_battery"
+};
+
+#define MAX_POWER_CHANGED 0x80
+#define POWER_STATE_CHANGED 0x81
+#define STEADY_STATE_POWER_CHANGED 0x83
+#define POWER_PROP_CHANGE_EVENT 0x84
+#define IMPEDANCED_CHNGED 0x85
+#define VOLTAGE_CURRENT_CHANGED 0x86
+
+static long long dptf_participant_type(acpi_handle handle)
+{
+ unsigned long long ptype;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(handle, "PTYP", NULL, &ptype);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ return ptype;
+}
+
+static void dptf_power_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct platform_device *pdev = data;
+ char *attr;
+
+ switch (event) {
+ case POWER_STATE_CHANGED:
+ attr = "platform_power_source";
+ break;
+ case POWER_PROP_CHANGE_EVENT:
+ attr = "rest_of_platform_power_mw";
+ break;
+ case MAX_POWER_CHANGED:
+ attr = "max_platform_power_mw";
+ break;
+ case STEADY_STATE_POWER_CHANGED:
+ attr = "max_steady_state_power_mw";
+ break;
+ case VOLTAGE_CURRENT_CHANGED:
+ attr = "no_load_voltage_mv";
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event);
+ return;
+ }
+
+ /*
+ * Notify that an attribute is changed, so that user space can read
+ * again.
+ */
+ if (dptf_participant_type(handle) == 0x0CULL)
+ sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr);
+ else
+ sysfs_notify(&pdev->dev.kobj, "dptf_power", attr);
+}
+
static int dptf_power_add(struct platform_device *pdev)
{
+ const struct attribute_group *attr_group;
struct acpi_device *acpi_dev;
- acpi_status status;
unsigned long long ptype;
int result;
@@ -71,17 +179,29 @@ static int dptf_power_add(struct platform_device *pdev)
if (!acpi_dev)
return -ENODEV;
- status = acpi_evaluate_integer(acpi_dev->handle, "PTYP", NULL, &ptype);
- if (ACPI_FAILURE(status))
+ ptype = dptf_participant_type(acpi_dev->handle);
+ if (ptype == 0x11)
+ attr_group = &dptf_power_attribute_group;
+ else if (ptype == 0x0C)
+ attr_group = &dptf_battery_attribute_group;
+ else
return -ENODEV;
- if (ptype != 0x11)
- return -ENODEV;
+ result = acpi_install_notify_handler(acpi_dev->handle,
+ ACPI_DEVICE_NOTIFY,
+ dptf_power_notify,
+ (void *)pdev);
+ if (result)
+ return result;
result = sysfs_create_group(&pdev->dev.kobj,
- &dptf_power_attribute_group);
- if (result)
+ attr_group);
+ if (result) {
+ acpi_remove_notify_handler(acpi_dev->handle,
+ ACPI_DEVICE_NOTIFY,
+ dptf_power_notify);
return result;
+ }
platform_set_drvdata(pdev, acpi_dev);
@@ -90,14 +210,23 @@ static int dptf_power_add(struct platform_device *pdev)
static int dptf_power_remove(struct platform_device *pdev)
{
+ struct acpi_device *acpi_dev = platform_get_drvdata(pdev);
+
+ acpi_remove_notify_handler(acpi_dev->handle,
+ ACPI_DEVICE_NOTIFY,
+ dptf_power_notify);
- sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
+ if (dptf_participant_type(acpi_dev->handle) == 0x0CULL)
+ sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group);
+ else
+ sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
return 0;
}
static const struct acpi_device_id int3407_device_ids[] = {
{"INT3407", 0},
+ {"INT3532", 0},
{"INTC1047", 0},
{"", 0},
};
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c44448ab19ef..04ce2b96c3da 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -34,7 +34,6 @@
#define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
-#define ACPI_EC_FILE_INFO "info"
/* EC status register */
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
@@ -1783,13 +1782,14 @@ static void __init acpi_ec_ecdt_start(void)
return;
status = acpi_get_handle(NULL, ecdt_ptr->id, &handle);
- if (ACPI_FAILURE(status))
- return;
+ if (ACPI_SUCCESS(status)) {
+ boot_ec->handle = handle;
- boot_ec->handle = handle;
+ /* Add a special ACPI device object to represent the boot EC. */
+ acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC);
+ }
- /* Add a special ACPI device object to represent the boot EC. */
- acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC);
+ acpi_put_table((struct acpi_table_header *)ecdt_ptr);
}
/*
@@ -1891,12 +1891,12 @@ void __init acpi_ec_ecdt_probe(void)
* Asus X50GL:
* https://bugzilla.kernel.org/show_bug.cgi?id=11880
*/
- return;
+ goto out;
}
ec = acpi_ec_alloc();
if (!ec)
- return;
+ goto out;
if (EC_FLAGS_CORRECT_ECDT) {
ec->command_addr = ecdt_ptr->data.address;
@@ -1922,13 +1922,16 @@ void __init acpi_ec_ecdt_probe(void)
ret = acpi_ec_setup(ec, NULL);
if (ret) {
acpi_ec_free(ec);
- return;
+ goto out;
}
boot_ec = ec;
boot_ec_is_ecdt = true;
pr_info("Boot ECDT EC used to handle transactions\n");
+
+out:
+ acpi_put_table((struct acpi_table_header *)ecdt_ptr);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c
index aba0d0027586..ccd900690b6f 100644
--- a/drivers/acpi/evged.c
+++ b/drivers/acpi/evged.c
@@ -79,6 +79,8 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
struct resource r;
struct acpi_resource_irq *p = &ares->data.irq;
struct acpi_resource_extended_irq *pext = &ares->data.extended_irq;
+ char ev_name[5];
+ u8 trigger;
if (ares->type == ACPI_RESOURCE_TYPE_END_TAG)
return AE_OK;
@@ -87,14 +89,28 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
dev_err(dev, "unable to parse IRQ resource\n");
return AE_ERROR;
}
- if (ares->type == ACPI_RESOURCE_TYPE_IRQ)
+ if (ares->type == ACPI_RESOURCE_TYPE_IRQ) {
gsi = p->interrupts[0];
- else
+ trigger = p->triggering;
+ } else {
gsi = pext->interrupts[0];
+ trigger = pext->triggering;
+ }
irq = r.start;
- if (ACPI_FAILURE(acpi_get_handle(handle, "_EVT", &evt_handle))) {
+ switch (gsi) {
+ case 0 ... 255:
+ sprintf(ev_name, "_%c%02hhX",
+ trigger == ACPI_EDGE_SENSITIVE ? 'E' : 'L', gsi);
+
+ if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
+ break;
+ /* fall through */
+ default:
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle)))
+ break;
+
dev_err(dev, "cannot locate _EVT method\n");
return AE_ERROR;
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index ed3d2182cf2c..606da5d77ad3 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -31,8 +31,6 @@
ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link"
-#define ACPI_PCI_LINK_FILE_INFO "info"
-#define ACPI_PCI_LINK_FILE_STATUS "state"
#define ACPI_PCI_LINK_MAX_POSSIBLE 16
static int acpi_pci_link_add(struct acpi_device *device,
diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
index 7ccd7d9660bc..a5101b07611a 100644
--- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
+++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
@@ -102,6 +102,7 @@ static struct intel_pmic_opregion_data chtdc_ti_pmic_opregion_data = {
.power_table_count = ARRAY_SIZE(chtdc_ti_power_table),
.thermal_table = chtdc_ti_thermal_table,
.thermal_table_count = ARRAY_SIZE(chtdc_ti_thermal_table),
+ .pmic_i2c_address = 0x5e,
};
static int chtdc_ti_pmic_opregion_probe(struct platform_device *pdev)
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index fe1e7bc91a5e..837b875d075e 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -36,8 +36,6 @@
ACPI_MODULE_NAME("power");
#define ACPI_POWER_CLASS "power_resource"
#define ACPI_POWER_DEVICE_NAME "Power Resource"
-#define ACPI_POWER_FILE_INFO "info"
-#define ACPI_POWER_FILE_STATUS "state"
#define ACPI_POWER_RESOURCE_STATE_OFF 0x00
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index dcc289e30166..75534c5b5433 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -308,11 +308,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
if (ret)
return ret;
- /*
- * It is expected that there will be at least 2 states, C1 and
- * something else (C2 or C3), so fail if that is not the case.
- */
- if (pr->power.count < 2)
+ if (!pr->power.count)
return -EFAULT;
pr->flags.has_cst = 1;
@@ -468,8 +464,7 @@ static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
if (pr->power.states[i].valid) {
pr->power.count = i;
- if (pr->power.states[i].type >= ACPI_STATE_C2)
- pr->flags.power = 1;
+ pr->flags.power = 1;
}
}
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 6e88224f60f0..f158b8c30113 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -28,9 +28,6 @@
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
-#define ACPI_SBS_FILE_INFO "info"
-#define ACPI_SBS_FILE_STATE "state"
-#define ACPI_SBS_FILE_ALARM "alarm"
#define ACPI_BATTERY_DIR_NAME "BAT%i"
#define ACPI_AC_DIR_NAME "AC0"
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 6d3448895382..5287ab98b8c1 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2157,10 +2157,13 @@ static void __init acpi_get_spcr_uart_addr(void)
status = acpi_get_table(ACPI_SIG_SPCR, 0,
(struct acpi_table_header **)&spcr_ptr);
- if (ACPI_SUCCESS(status))
- spcr_uart_addr = spcr_ptr->serial_port.address;
- else
- printk(KERN_WARNING PREFIX "STAO table present, but SPCR is missing\n");
+ if (ACPI_FAILURE(status)) {
+ pr_warn(PREFIX "STAO table present, but SPCR is missing\n");
+ return;
+ }
+
+ spcr_uart_addr = spcr_ptr->serial_port.address;
+ acpi_put_table((struct acpi_table_header *)spcr_ptr);
}
static bool acpi_scan_initialized;
@@ -2196,10 +2199,12 @@ int __init acpi_scan_init(void)
(struct acpi_table_header **)&stao_ptr);
if (ACPI_SUCCESS(status)) {
if (stao_ptr->header.length > sizeof(struct acpi_table_stao))
- printk(KERN_INFO PREFIX "STAO Name List not yet supported.");
+ pr_info(PREFIX "STAO Name List not yet supported.\n");
if (stao_ptr->ignore_uart)
acpi_get_spcr_uart_addr();
+
+ acpi_put_table((struct acpi_table_header *)stao_ptr);
}
acpi_gpe_apply_masked_gpes();
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 31c9d0c8ae11..aff13bf4d947 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -1290,8 +1290,10 @@ static void acpi_sleep_hibernate_setup(void)
return;
acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
- if (facs)
+ if (facs) {
s4_hardware_signature = facs->hardware_signature;
+ acpi_put_table((struct acpi_table_header *)facs);
+ }
}
#else /* !CONFIG_HIBERNATION */
static inline void acpi_sleep_hibernate_setup(void) {}
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index c60d2c6d31d6..3a89909b50a6 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -993,8 +993,10 @@ void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
error = kobject_init_and_add(&hotplug->kobj,
&acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name);
- if (error)
+ if (error) {
+ kobject_put(&hotplug->kobj);
goto err_out;
+ }
kobject_uevent(&hotplug->kobj, KOBJ_ADD);
return;
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 804ac0df58ec..838b719ec7ce 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -606,6 +606,31 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
}
/**
+ * acpi_evaluate_reg: Evaluate _REG method to register OpRegion presence
+ * @handle: ACPI device handle
+ * @space_id: ACPI address space id to register OpRegion presence for
+ * @function: Parameter to pass to _REG one of ACPI_REG_CONNECT or
+ * ACPI_REG_DISCONNECT
+ *
+ * Evaluate device's _REG method to register OpRegion presence.
+ */
+acpi_status acpi_evaluate_reg(acpi_handle handle, u8 space_id, u32 function)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object params[2];
+
+ params[0].type = ACPI_TYPE_INTEGER;
+ params[0].integer.value = space_id;
+ params[1].type = ACPI_TYPE_INTEGER;
+ params[1].integer.value = function;
+ arg_list.count = 2;
+ arg_list.pointer = params;
+
+ return acpi_evaluate_object(handle, "_REG", &arg_list, NULL);
+}
+EXPORT_SYMBOL(acpi_evaluate_reg);
+
+/**
* acpi_evaluate_dsm - evaluate device's _DSM method
* @handle: ACPI device handle
* @guid: GUID of requested functions, should be 16 bytes
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index b4994e50608d..2499d7e3c710 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -361,6 +361,16 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "JV50"),
},
},
+ {
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
+ .callback = video_detect_force_native,
+ .ident = "Acer TravelMate 5735Z",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
+ DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
+ },
+ },
/*
* Desktops which falsely report a backlight and which our heuristics
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index b3869951c0eb..b4c92cee13f8 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -385,19 +385,12 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
- union acpi_object params[2];
- struct acpi_object_list arg_list;
list_for_each_entry(func, &slot->funcs, sibling) {
- arg_list.count = 2;
- arg_list.pointer = params;
- params[0].type = ACPI_TYPE_INTEGER;
- params[0].integer.value = ACPI_ADR_SPACE_PCI_CONFIG;
- params[1].type = ACPI_TYPE_INTEGER;
- params[1].integer.value = 1;
/* _REG is optional, we don't care about if there is failure */
- acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list,
- NULL);
+ acpi_evaluate_reg(func_to_handle(func),
+ ACPI_ADR_SPACE_PCI_CONFIG,
+ ACPI_REG_CONNECT);
}
}
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index a92bea7184a8..5afb6ceb284f 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -44,6 +44,7 @@ acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
u64 arg);
acpi_status acpi_evaluate_ej0(acpi_handle handle);
acpi_status acpi_evaluate_lck(acpi_handle handle, int lock);
+acpi_status acpi_evaluate_reg(acpi_handle handle, u8 space_id, u32 function);
bool acpi_ata_match(acpi_handle handle);
bool acpi_bay_match(acpi_handle handle);
bool acpi_dock_match(acpi_handle handle);
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 49b519f36b69..1dc8d262035b 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -12,7 +12,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20200326
+#define ACPI_CA_VERSION 0x20200430
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index e3f1cddb4ac8..517a5231cc1b 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -33,6 +33,9 @@ struct ghes_estatus_node {
struct llist_node llnode;
struct acpi_hest_generic *generic;
struct ghes *ghes;
+
+ int task_work_cpu;
+ struct callback_head task_work;
};
struct ghes_estatus_cache {
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 6e6c71cdfa13..7e07f4f490cb 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3048,6 +3048,7 @@ enum mf_flags {
};
extern int memory_failure(unsigned long pfn, int flags);
extern void memory_failure_queue(unsigned long pfn, int flags);
+extern void memory_failure_queue_kick(int cpu);
extern int unpoison_memory(unsigned long pfn);
extern int get_hwpoison_page(struct page *page);
#define put_hwpoison_page(page) put_page(page)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index dd3862fcf2e9..ababa368cb68 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1496,7 +1496,7 @@ static void memory_failure_work_func(struct work_struct *work)
unsigned long proc_flags;
int gotten;
- mf_cpu = this_cpu_ptr(&memory_failure_cpu);
+ mf_cpu = container_of(work, struct memory_failure_cpu, work);
for (;;) {
spin_lock_irqsave(&mf_cpu->lock, proc_flags);
gotten = kfifo_get(&mf_cpu->fifo, &entry);
@@ -1510,6 +1510,19 @@ static void memory_failure_work_func(struct work_struct *work)
}
}
+/*
+ * Process memory_failure work queued on the specified CPU.
+ * Used to avoid return-to-userspace racing with the memory_failure workqueue.
+ */
+void memory_failure_queue_kick(int cpu)
+{
+ struct memory_failure_cpu *mf_cpu;
+
+ mf_cpu = &per_cpu(memory_failure_cpu, cpu);
+ cancel_work_sync(&mf_cpu->work);
+ memory_failure_work_func(&mf_cpu->work);
+}
+
static int __init memory_failure_init(void)
{
struct memory_failure_cpu *mf_cpu;