Commit 118d6e98 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 355ba37d 48ccdedd
...@@ -27,10 +27,12 @@ KernelVersion: v4.10 ...@@ -27,10 +27,12 @@ KernelVersion: v4.10
Contact: linux-acpi@vger.kernel.org Contact: linux-acpi@vger.kernel.org
Description: Description:
(RO) Display the platform power source (RO) Display the platform power source
0x00 = DC bits[3:0] Current power source
0x01 = AC 0x00 = DC
0x02 = USB 0x01 = AC
0x03 = Wireless Charger 0x02 = USB
0x03 = Wireless Charger
bits[7:4] Power source sequence number
What: /sys/bus/platform/devices/INT3407:00/dptf_power/battery_steady_power What: /sys/bus/platform/devices/INT3407:00/dptf_power/battery_steady_power
Date: Jul, 2016 Date: Jul, 2016
...@@ -38,3 +40,55 @@ KernelVersion: v4.10 ...@@ -38,3 +40,55 @@ KernelVersion: v4.10
Contact: linux-acpi@vger.kernel.org Contact: linux-acpi@vger.kernel.org
Description: Description:
(RO) The maximum sustained power for battery in milliwatts. (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.
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/irq_work.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <linux/smp.h> #include <linux/smp.h>
...@@ -269,6 +270,7 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr) ...@@ -269,6 +270,7 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
int apei_claim_sea(struct pt_regs *regs) int apei_claim_sea(struct pt_regs *regs)
{ {
int err = -ENOENT; int err = -ENOENT;
bool return_to_irqs_enabled;
unsigned long current_flags; unsigned long current_flags;
if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES)) if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
...@@ -276,6 +278,12 @@ int apei_claim_sea(struct pt_regs *regs) ...@@ -276,6 +278,12 @@ int apei_claim_sea(struct pt_regs *regs)
current_flags = local_daif_save_flags(); 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 * SEA can interrupt SError, mask it and describe this as an NMI so
* that APEI defers the handling. * that APEI defers the handling.
...@@ -284,6 +292,23 @@ int apei_claim_sea(struct pt_regs *regs) ...@@ -284,6 +292,23 @@ int apei_claim_sea(struct pt_regs *regs)
nmi_enter(); nmi_enter();
err = ghes_notify_sea(); err = ghes_notify_sea();
nmi_exit(); 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); local_daif_restore(current_flags);
return err; return err;
......
...@@ -635,11 +635,13 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) ...@@ -635,11 +635,13 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
inf = esr_to_fault_info(esr); inf = esr_to_fault_info(esr);
/* if (user_mode(regs) && apei_claim_sea(regs) == 0) {
* Return value ignored as we rely on signal merging. /*
* Future patches will make this more robust. * APEI claimed this as a firmware-first notification.
*/ * Some processing deferred to task_work before ret_to_user().
apei_claim_sea(regs); */
return 0;
}
if (esr & ESR_ELx_FnV) if (esr & ESR_ELx_FnV)
siaddr = NULL; siaddr = NULL;
......
...@@ -745,7 +745,7 @@ static const struct acpi_debugger_ops acpi_aml_debugger = { ...@@ -745,7 +745,7 @@ static const struct acpi_debugger_ops acpi_aml_debugger = {
.notify_command_complete = acpi_aml_notify_command_complete, .notify_command_complete = acpi_aml_notify_command_complete,
}; };
int __init acpi_aml_init(void) static int __init acpi_aml_init(void)
{ {
int ret; int ret;
...@@ -771,7 +771,7 @@ int __init acpi_aml_init(void) ...@@ -771,7 +771,7 @@ int __init acpi_aml_init(void)
return 0; return 0;
} }
void __exit acpi_aml_exit(void) static void __exit acpi_aml_exit(void)
{ {
if (acpi_aml_initialized) { if (acpi_aml_initialized) {
acpi_unregister_debugger(&acpi_aml_debugger); acpi_unregister_debugger(&acpi_aml_debugger);
......
...@@ -151,10 +151,11 @@ void acpi_init_lpit(void) ...@@ -151,10 +151,11 @@ void acpi_init_lpit(void)
struct acpi_table_lpit *lpit; struct acpi_table_lpit *lpit;
status = acpi_get_table(ACPI_SIG_LPIT, 0, (struct acpi_table_header **)&lpit); status = acpi_get_table(ACPI_SIG_LPIT, 0, (struct acpi_table_header **)&lpit);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return; return;
lpit_process((u64)lpit + sizeof(*lpit), lpit_process((u64)lpit + sizeof(*lpit),
(u64)lpit + lpit->header.length); (u64)lpit + lpit->header.length);
acpi_put_table((struct acpi_table_header *)lpit);
} }
...@@ -73,6 +73,7 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) ...@@ -73,6 +73,7 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void)
} }
if (acpi_watchdog_uses_rtc(wdat)) { 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"); pr_info("Skipping WDAT on this system because it uses RTC SRAM\n");
return NULL; return NULL;
} }
...@@ -117,12 +118,12 @@ void __init acpi_watchdog_init(void) ...@@ -117,12 +118,12 @@ void __init acpi_watchdog_init(void)
/* Watchdog disabled by BIOS */ /* Watchdog disabled by BIOS */
if (!(wdat->flags & ACPI_WDAT_ENABLED)) if (!(wdat->flags & ACPI_WDAT_ENABLED))
return; goto fail_put_wdat;
/* Skip legacy PCI WDT devices */ /* Skip legacy PCI WDT devices */
if (wdat->pci_segment != 0xff || wdat->pci_bus != 0xff || if (wdat->pci_segment != 0xff || wdat->pci_bus != 0xff ||
wdat->pci_device != 0xff || wdat->pci_function != 0xff) wdat->pci_device != 0xff || wdat->pci_function != 0xff)
return; goto fail_put_wdat;
INIT_LIST_HEAD(&resource_list); INIT_LIST_HEAD(&resource_list);
...@@ -188,4 +189,6 @@ void __init acpi_watchdog_init(void) ...@@ -188,4 +189,6 @@ void __init acpi_watchdog_init(void)
fail_free_resource_list: fail_free_resource_list:
resource_list_free(&resource_list); resource_list_free(&resource_list);
fail_put_wdat:
acpi_put_table((struct acpi_table_header *)wdat);
} }
...@@ -290,6 +290,7 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list); ...@@ -290,6 +290,7 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
#ifdef ACPI_DEBUGGER #ifdef ACPI_DEBUGGER
ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE); 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(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_ini_methods);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support); ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support);
......
...@@ -640,10 +640,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { ...@@ -640,10 +640,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_NIC", METHOD_0ARGS, /* ACPI 6.3 */ {{"_NIC", METHOD_0ARGS, /* ACPI 6.3 */
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, 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)}}, 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)}}, METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
{{"_NTT", METHOD_0ARGS, {{"_NTT", METHOD_0ARGS,
......
...@@ -27,7 +27,6 @@ static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE]; ...@@ -27,7 +27,6 @@ static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE];
static u16 acpi_gbl_lo_history = 0; static u16 acpi_gbl_lo_history = 0;
static u16 acpi_gbl_num_history = 0; static u16 acpi_gbl_num_history = 0;
static u16 acpi_gbl_next_history_index = 0; static u16 acpi_gbl_next_history_index = 0;
u32 acpi_gbl_next_cmd_num = 1;
/******************************************************************************* /*******************************************************************************
* *
......
...@@ -177,7 +177,10 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, ...@@ -177,7 +177,10 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
arg->common.value.string, ACPI_TYPE_ANY, arg->common.value.string, ACPI_TYPE_ANY,
ACPI_IMODE_LOAD_PASS1, flags, ACPI_IMODE_LOAD_PASS1, flags,
walk_state, &node); 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, ACPI_ERROR_NAMESPACE(walk_state->scope_info,
arg->common.value.string, status); arg->common.value.string, status);
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
...@@ -514,13 +517,20 @@ acpi_ds_create_field(union acpi_parse_object *op, ...@@ -514,13 +517,20 @@ acpi_ds_create_field(union acpi_parse_object *op,
info.region_node = region_node; info.region_node = region_node;
status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); 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 == if (info.region_node->object->region.space_id ==
ACPI_ADR_SPACE_PLATFORM_COMM ACPI_ADR_SPACE_PLATFORM_COMM) {
&& !(region_node->object->field.internal_pcc_buffer = region_node->object->field.internal_pcc_buffer =
ACPI_ALLOCATE_ZEROED(info.region_node->object->region. ACPI_ALLOCATE_ZEROED(info.region_node->object->region.
length))) { length);
return_ACPI_STATUS(AE_NO_MEMORY); if (!region_node->object->field.internal_pcc_buffer) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
} }
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
......
...@@ -22,7 +22,7 @@ ACPI_MODULE_NAME("exfield") ...@@ -22,7 +22,7 @@ ACPI_MODULE_NAME("exfield")
*/ */
#define ACPI_INVALID_PROTOCOL_ID 0x80 #define ACPI_INVALID_PROTOCOL_ID 0x80
#define ACPI_MAX_PROTOCOL_ID 0x0F #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, /* 0 - reserved */
ACPI_INVALID_PROTOCOL_ID, /* 1 - reserved */ ACPI_INVALID_PROTOCOL_ID, /* 1 - reserved */
0x00, /* 2 - ATTRIB_QUICK */ 0x00, /* 2 - ATTRIB_QUICK */
......
...@@ -119,7 +119,7 @@ static int __init bert_init(void) ...@@ -119,7 +119,7 @@ static int __init bert_init(void)
rc = bert_check_table(bert_tab); rc = bert_check_table(bert_tab);
if (rc) { if (rc) {
pr_err(FW_BUG "table invalid.\n"); pr_err(FW_BUG "table invalid.\n");
return rc; goto out_put_bert_tab;
} }
region_len = bert_tab->region_length; region_len = bert_tab->region_length;
...@@ -127,7 +127,7 @@ static int __init bert_init(void) ...@@ -127,7 +127,7 @@ static int __init bert_init(void)
rc = apei_resources_add(&bert_resources, bert_tab->address, rc = apei_resources_add(&bert_resources, bert_tab->address,
region_len, true); region_len, true);
if (rc) if (rc)
return rc; goto out_put_bert_tab;
rc = apei_resources_request(&bert_resources, "APEI BERT"); rc = apei_resources_request(&bert_resources, "APEI BERT");
if (rc) if (rc)
goto out_fini; goto out_fini;
...@@ -142,6 +142,8 @@ static int __init bert_init(void) ...@@ -142,6 +142,8 @@ static int __init bert_init(void)
apei_resources_release(&bert_resources); apei_resources_release(&bert_resources);
out_fini: out_fini:
apei_resources_fini(&bert_resources); apei_resources_fini(&bert_resources);
out_put_bert_tab:
acpi_put_table((struct acpi_table_header *)bert_tab);
return rc; return rc;
} }
......
...@@ -692,7 +692,7 @@ static int __init einj_init(void) ...@@ -692,7 +692,7 @@ static int __init einj_init(void)
rc = einj_check_table(einj_tab); rc = einj_check_table(einj_tab);
if (rc) { if (rc) {
pr_warn(FW_BUG "Invalid EINJ table.\n"); pr_warn(FW_BUG "Invalid EINJ table.\n");
return -EINVAL; goto err_put_table;
} }
rc = -ENOMEM; rc = -ENOMEM;
...@@ -760,6 +760,8 @@ static int __init einj_init(void) ...@@ -760,6 +760,8 @@ static int __init einj_init(void)
err_fini: err_fini:
apei_resources_fini(&einj_resources); apei_resources_fini(&einj_resources);
debugfs_remove_recursive(einj_debug_dir); debugfs_remove_recursive(einj_debug_dir);
err_put_table:
acpi_put_table((struct acpi_table_header *)einj_tab);
return rc; return rc;
} }
...@@ -780,6 +782,7 @@ static void __exit einj_exit(void) ...@@ -780,6 +782,7 @@ static void __exit einj_exit(void)
apei_resources_release(&einj_resources); apei_resources_release(&einj_resources);
apei_resources_fini(&einj_resources); apei_resources_fini(&einj_resources);
debugfs_remove_recursive(einj_debug_dir); debugfs_remove_recursive(einj_debug_dir);
acpi_put_table((struct acpi_table_header *)einj_tab);
} }
module_init(einj_init); module_init(einj_init);
......
...@@ -1122,7 +1122,7 @@ static int __init erst_init(void) ...@@ -1122,7 +1122,7 @@ static int __init erst_init(void)
rc = erst_check_table(erst_tab); rc = erst_check_table(erst_tab);
if (rc) { if (rc) {
pr_err(FW_BUG "ERST table is invalid.\n"); pr_err(FW_BUG "ERST table is invalid.\n");
goto err; goto err_put_erst_tab;
} }
apei_resources_init(&erst_resources); apei_resources_init(&erst_resources);
...@@ -1196,6 +1196,8 @@ static int __init erst_init(void) ...@@ -1196,6 +1196,8 @@ static int __init erst_init(void)
apei_resources_release(&erst_resources); apei_resources_release(&erst_resources);
err_fini: err_fini:
apei_resources_fini(&erst_resources); apei_resources_fini(&erst_resources);
err_put_erst_tab:
acpi_put_table((struct acpi_table_header *)erst_tab);
err: err:
erst_disable = 1; erst_disable = 1;
return rc; return rc;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <linux/sched/clock.h> #include <linux/sched/clock.h>
#include <linux/uuid.h> #include <linux/uuid.h>
#include <linux/ras.h> #include <linux/ras.h>
#include <linux/task_work.h>
#include <acpi/actbl1.h> #include <acpi/actbl1.h>
#include <acpi/ghes.h> #include <acpi/ghes.h>
...@@ -408,23 +409,46 @@ static void ghes_clear_estatus(struct ghes *ghes, ...@@ -408,23 +409,46 @@ static void ghes_clear_estatus(struct ghes *ghes,
ghes_ack_error(ghes->generic_v2); 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; unsigned long pfn;
int flags = -1; int flags = -1;
int sec_sev = ghes_severity(gdata->error_severity); int sec_sev = ghes_severity(gdata->error_severity);
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); 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)) if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
return; return false;
pfn = mem_err->physical_addr >> PAGE_SHIFT; pfn = mem_err->physical_addr >> PAGE_SHIFT;
if (!pfn_valid(pfn)) { if (!pfn_valid(pfn)) {
pr_warn_ratelimited(FW_WARN GHES_PFX pr_warn_ratelimited(FW_WARN GHES_PFX
"Invalid address in generic error data: %#llx\n", "Invalid address in generic error data: %#llx\n",
mem_err->physical_addr); mem_err->physical_addr);
return; return false;
} }
/* iff following two events can be handled properly by now */ /* 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 ...@@ -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) if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
flags = 0; flags = 0;
if (flags != -1) if (flags != -1) {
memory_failure_queue(pfn, flags); 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) ...@@ -484,7 +511,7 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
#endif #endif
} }
static void ghes_do_proc(struct ghes *ghes, static bool ghes_do_proc(struct ghes *ghes,
const struct acpi_hest_generic_status *estatus) const struct acpi_hest_generic_status *estatus)
{ {
int sev, sec_sev; int sev, sec_sev;
...@@ -492,6 +519,7 @@ static void ghes_do_proc(struct ghes *ghes, ...@@ -492,6 +519,7 @@ static void ghes_do_proc(struct ghes *ghes,
guid_t *sec_type; guid_t *sec_type;
const guid_t *fru_id = &guid_null; const guid_t *fru_id = &guid_null;
char *fru_text = ""; char *fru_text = "";
bool queued = false;
sev = ghes_severity(estatus->error_severity); sev = ghes_severity(estatus->error_severity);
apei_estatus_for_each_section(estatus, gdata) { apei_estatus_for_each_section(estatus, gdata) {
...@@ -509,7 +537,7 @@ static void ghes_do_proc(struct ghes *ghes, ...@@ -509,7 +537,7 @@ static void ghes_do_proc(struct ghes *ghes,
ghes_edac_report_mem_error(sev, mem_err); ghes_edac_report_mem_error(sev, mem_err);
arch_apei_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)) { else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
ghes_handle_aer(gdata); ghes_handle_aer(gdata);
...@@ -526,6 +554,8 @@ static void ghes_do_proc(struct ghes *ghes, ...@@ -526,6 +554,8 @@ static void ghes_do_proc(struct ghes *ghes,
gdata->error_data_length); gdata->error_data_length);
} }
} }
return queued;
} }
static void __ghes_print_estatus(const char *pfx, static void __ghes_print_estatus(const char *pfx,
...@@ -821,7 +851,9 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) ...@@ -821,7 +851,9 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
struct ghes_estatus_node *estatus_node; struct ghes_estatus_node *estatus_node;
struct acpi_hest_generic *generic; struct acpi_hest_generic *generic;
struct acpi_hest_generic_status *estatus; struct acpi_hest_generic_status *estatus;
bool task_work_pending;
u32 len, node_len; u32 len, node_len;
int ret;
llnode = llist_del_all(&ghes_estatus_llist); llnode = llist_del_all(&ghes_estatus_llist);
/* /*
...@@ -836,14 +868,26 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) ...@@ -836,14 +868,26 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
estatus = GHES_ESTATUS_FROM_NODE(estatus_node); estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
len = cper_estatus_len(estatus); len = cper_estatus_len(estatus);
node_len = GHES_ESTATUS_NODE_LEN(len); 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)) { if (!ghes_estatus_cached(estatus)) {
generic = estatus_node->generic; generic = estatus_node->generic;
if (ghes_print_estatus(NULL, generic, estatus)) if (ghes_print_estatus(NULL, generic, estatus))
ghes_estatus_cache_add(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; llnode = next;
} }
} }
...@@ -903,6 +947,7 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes, ...@@ -903,6 +947,7 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
estatus_node->ghes = ghes; estatus_node->ghes = ghes;
estatus_node->generic = ghes->generic; estatus_node->generic = ghes->generic;
estatus_node->task_work.func = NULL;
estatus = GHES_ESTATUS_FROM_NODE(estatus_node); estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) { if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) {
......
...@@ -243,8 +243,8 @@ void __init acpi_hest_init(void) ...@@ -243,8 +243,8 @@ void __init acpi_hest_init(void)
} else if (ACPI_FAILURE(status)) { } else if (ACPI_FAILURE(status)) {
const char *msg = acpi_format_exception(status); const char *msg = acpi_format_exception(status);
pr_err(HEST_PFX "Failed to get table, %s\n", msg); pr_err(HEST_PFX "Failed to get table, %s\n", msg);
rc = -EINVAL; hest_disable = HEST_DISABLED;
goto err; return;
} }
rc = apei_hest_parse(hest_parse_cmc, NULL); rc = apei_hest_parse(hest_parse_cmc, NULL);
...@@ -266,4 +266,5 @@ void __init acpi_hest_init(void) ...@@ -266,4 +266,5 @@ void __init acpi_hest_init(void)
return; return;
err: err:
hest_disable = HEST_DISABLED; hest_disable = HEST_DISABLED;
acpi_put_table((struct acpi_table_header *)hest_tab);
} }
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#define PREFIX "ACPI: " #define PREFIX "ACPI: "
#define ACPI_BUTTON_CLASS "button" #define ACPI_BUTTON_CLASS "button"
#define ACPI_BUTTON_FILE_INFO "info"
#define ACPI_BUTTON_FILE_STATE "state" #define ACPI_BUTTON_FILE_STATE "state"
#define ACPI_BUTTON_TYPE_UNKNOWN 0x00 #define ACPI_BUTTON_TYPE_UNKNOWN 0x00
#define ACPI_BUTTON_NOTIFY_STATUS 0x80 #define ACPI_BUTTON_NOTIFY_STATUS 0x80
......
...@@ -350,7 +350,7 @@ static void cppc_chan_tx_done(struct mbox_client *cl, void *msg, int ret) ...@@ -350,7 +350,7 @@ static void cppc_chan_tx_done(struct mbox_client *cl, void *msg, int ret)
*(u16 *)msg, ret); *(u16 *)msg, ret);
} }
struct mbox_client cppc_mbox_cl = { static struct mbox_client cppc_mbox_cl = {
.tx_done = cppc_chan_tx_done, .tx_done = cppc_chan_tx_done,
.knows_txdone = true, .knows_txdone = true,
}; };
...@@ -597,7 +597,7 @@ bool __weak cpc_ffh_supported(void) ...@@ -597,7 +597,7 @@ bool __weak cpc_ffh_supported(void)
* *
* Return: 0 for success, errno for failure * 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) if (pcc_ss_id < 0 || pcc_ss_id >= MAX_PCC_SUBSPACES)
return -EINVAL; return -EINVAL;
...@@ -846,6 +846,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) ...@@ -846,6 +846,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
"acpi_cppc"); "acpi_cppc");
if (ret) { if (ret) {
per_cpu(cpc_desc_ptr, pr->id) = NULL; per_cpu(cpc_desc_ptr, pr->id) = NULL;
kobject_put(&cpc_ptr->kobj);
goto out_free; goto out_free;
} }
......
...@@ -10,12 +10,19 @@ ...@@ -10,12 +10,19 @@
#include <linux/platform_device.h> #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 * PMAX : Maximum platform powe
* PSRC : Platform power source * PSRC : Platform power source
* ARTG : Adapter rating * ARTG : Adapter rating
* CTYP : Charger type * CTYP : Charger type
* PBSS : Battery steady power * 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) \ #define DPTF_POWER_SHOW(name, object) \
static ssize_t name##_show(struct device *dev,\ static ssize_t name##_show(struct device *dev,\
...@@ -39,12 +46,42 @@ DPTF_POWER_SHOW(platform_power_source, PSRC) ...@@ -39,12 +46,42 @@ DPTF_POWER_SHOW(platform_power_source, PSRC)
DPTF_POWER_SHOW(adapter_rating_mw, ARTG) DPTF_POWER_SHOW(adapter_rating_mw, ARTG)
DPTF_POWER_SHOW(battery_steady_power_mw, PBSS) DPTF_POWER_SHOW(battery_steady_power_mw, PBSS)
DPTF_POWER_SHOW(charger_type, CTYP) 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(max_platform_power_mw);
static DEVICE_ATTR_RO(platform_power_source); static DEVICE_ATTR_RO(platform_power_source);
static DEVICE_ATTR_RO(adapter_rating_mw); static DEVICE_ATTR_RO(adapter_rating_mw);
static DEVICE_ATTR_RO(battery_steady_power_mw); static DEVICE_ATTR_RO(battery_steady_power_mw);
static DEVICE_ATTR_RO(charger_type); 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[] = { static struct attribute *dptf_power_attrs[] = {
&dev_attr_max_platform_power_mw.attr, &dev_attr_max_platform_power_mw.attr,
...@@ -52,6 +89,8 @@ static struct attribute *dptf_power_attrs[] = { ...@@ -52,6 +89,8 @@ static struct attribute *dptf_power_attrs[] = {
&dev_attr_adapter_rating_mw.attr, &dev_attr_adapter_rating_mw.attr,
&dev_attr_battery_steady_power_mw.attr, &dev_attr_battery_steady_power_mw.attr,
&dev_attr_charger_type.attr, &dev_attr_charger_type.attr,
&dev_attr_rest_of_platform_power_mw.attr,
&dev_attr_prochot_confirm.attr,
NULL NULL
}; };
...@@ -60,10 +99,79 @@ static const struct attribute_group dptf_power_attribute_group = { ...@@ -60,10 +99,79 @@ static const struct attribute_group dptf_power_attribute_group = {
.name = "dptf_power" .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) static int dptf_power_add(struct platform_device *pdev)
{ {
const struct attribute_group *attr_group;
struct acpi_device *acpi_dev; struct acpi_device *acpi_dev;
acpi_status status;
unsigned long long ptype; unsigned long long ptype;
int result; int result;
...@@ -71,17 +179,29 @@ static int dptf_power_add(struct platform_device *pdev) ...@@ -71,17 +179,29 @@ static int dptf_power_add(struct platform_device *pdev)
if (!acpi_dev) if (!acpi_dev)
return -ENODEV; return -ENODEV;
status = acpi_evaluate_integer(acpi_dev->handle, "PTYP", NULL, &ptype); ptype = dptf_participant_type(acpi_dev->handle);
if (ACPI_FAILURE(status)) if (ptype == 0x11)
attr_group = &dptf_power_attribute_group;
else if (ptype == 0x0C)
attr_group = &dptf_battery_attribute_group;
else
return -ENODEV; return -ENODEV;
if (ptype != 0x11) result = acpi_install_notify_handler(acpi_dev->handle,
return -ENODEV; ACPI_DEVICE_NOTIFY,
dptf_power_notify,
(void *)pdev);
if (result)
return result;
result = sysfs_create_group(&pdev->dev.kobj, result = sysfs_create_group(&pdev->dev.kobj,
&dptf_power_attribute_group); attr_group);
if (result) if (result) {
acpi_remove_notify_handler(acpi_dev->handle,
ACPI_DEVICE_NOTIFY,
dptf_power_notify);
return result; return result;
}
platform_set_drvdata(pdev, acpi_dev); platform_set_drvdata(pdev, acpi_dev);
...@@ -90,14 +210,23 @@ static int dptf_power_add(struct platform_device *pdev) ...@@ -90,14 +210,23 @@ static int dptf_power_add(struct platform_device *pdev)
static int dptf_power_remove(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; return 0;
} }
static const struct acpi_device_id int3407_device_ids[] = { static const struct acpi_device_id int3407_device_ids[] = {
{"INT3407", 0}, {"INT3407", 0},
{"INT3532", 0},
{"INTC1047", 0}, {"INTC1047", 0},
{"", 0}, {"", 0},
}; };
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
/* EC status register */ /* EC status register */
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
...@@ -1783,13 +1782,14 @@ static void __init acpi_ec_ecdt_start(void) ...@@ -1783,13 +1782,14 @@ static void __init acpi_ec_ecdt_start(void)
return; return;
status = acpi_get_handle(NULL, ecdt_ptr->id, &handle); status = acpi_get_handle(NULL, ecdt_ptr->id, &handle);
if (ACPI_FAILURE(status)) if (ACPI_SUCCESS(status)) {
return; 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_put_table((struct acpi_table_header *)ecdt_ptr);
acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC);
} }
/* /*
...@@ -1891,12 +1891,12 @@ void __init acpi_ec_ecdt_probe(void) ...@@ -1891,12 +1891,12 @@ void __init acpi_ec_ecdt_probe(void)
* Asus X50GL: * Asus X50GL:
* https://bugzilla.kernel.org/show_bug.cgi?id=11880 * https://bugzilla.kernel.org/show_bug.cgi?id=11880
*/ */
return; goto out;
} }
ec = acpi_ec_alloc(); ec = acpi_ec_alloc();
if (!ec) if (!ec)
return; goto out;
if (EC_FLAGS_CORRECT_ECDT) { if (EC_FLAGS_CORRECT_ECDT) {
ec->command_addr = ecdt_ptr->data.address; ec->command_addr = ecdt_ptr->data.address;
...@@ -1922,13 +1922,16 @@ void __init acpi_ec_ecdt_probe(void) ...@@ -1922,13 +1922,16 @@ void __init acpi_ec_ecdt_probe(void)
ret = acpi_ec_setup(ec, NULL); ret = acpi_ec_setup(ec, NULL);
if (ret) { if (ret) {
acpi_ec_free(ec); acpi_ec_free(ec);
return; goto out;
} }
boot_ec = ec; boot_ec = ec;
boot_ec_is_ecdt = true; boot_ec_is_ecdt = true;
pr_info("Boot ECDT EC used to handle transactions\n"); pr_info("Boot ECDT EC used to handle transactions\n");
out:
acpi_put_table((struct acpi_table_header *)ecdt_ptr);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
......
...@@ -79,6 +79,8 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, ...@@ -79,6 +79,8 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
struct resource r; struct resource r;
struct acpi_resource_irq *p = &ares->data.irq; struct acpi_resource_irq *p = &ares->data.irq;
struct acpi_resource_extended_irq *pext = &ares->data.extended_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) if (ares->type == ACPI_RESOURCE_TYPE_END_TAG)
return AE_OK; return AE_OK;
...@@ -87,14 +89,28 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, ...@@ -87,14 +89,28 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
dev_err(dev, "unable to parse IRQ resource\n"); dev_err(dev, "unable to parse IRQ resource\n");
return AE_ERROR; return AE_ERROR;
} }
if (ares->type == ACPI_RESOURCE_TYPE_IRQ) if (ares->type == ACPI_RESOURCE_TYPE_IRQ) {
gsi = p->interrupts[0]; gsi = p->interrupts[0];
else trigger = p->triggering;
} else {
gsi = pext->interrupts[0]; gsi = pext->interrupts[0];
trigger = pext->triggering;
}
irq = r.start; 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"); dev_err(dev, "cannot locate _EVT method\n");
return AE_ERROR; return AE_ERROR;
} }
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
ACPI_MODULE_NAME("pci_link"); ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_CLASS "pci_irq_routing" #define ACPI_PCI_LINK_CLASS "pci_irq_routing"
#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" #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 #define ACPI_PCI_LINK_MAX_POSSIBLE 16
static int acpi_pci_link_add(struct acpi_device *device, static int acpi_pci_link_add(struct acpi_device *device,
......
...@@ -102,6 +102,7 @@ static struct intel_pmic_opregion_data chtdc_ti_pmic_opregion_data = { ...@@ -102,6 +102,7 @@ static struct intel_pmic_opregion_data chtdc_ti_pmic_opregion_data = {
.power_table_count = ARRAY_SIZE(chtdc_ti_power_table), .power_table_count = ARRAY_SIZE(chtdc_ti_power_table),
.thermal_table = chtdc_ti_thermal_table, .thermal_table = chtdc_ti_thermal_table,
.thermal_table_count = ARRAY_SIZE(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) static int chtdc_ti_pmic_opregion_probe(struct platform_device *pdev)
......
...@@ -36,8 +36,6 @@ ...@@ -36,8 +36,6 @@
ACPI_MODULE_NAME("power"); ACPI_MODULE_NAME("power");
#define ACPI_POWER_CLASS "power_resource" #define ACPI_POWER_CLASS "power_resource"
#define ACPI_POWER_DEVICE_NAME "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_OFF 0x00
#define ACPI_POWER_RESOURCE_STATE_ON 0x01 #define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
......
...@@ -308,11 +308,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) ...@@ -308,11 +308,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
if (ret) if (ret)
return ret; return ret;
/* if (!pr->power.count)
* 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)
return -EFAULT; return -EFAULT;
pr->flags.has_cst = 1; pr->flags.has_cst = 1;
...@@ -468,8 +464,7 @@ static int acpi_processor_get_cstate_info(struct acpi_processor *pr) ...@@ -468,8 +464,7 @@ static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
if (pr->power.states[i].valid) { if (pr->power.states[i].valid) {
pr->power.count = i; pr->power.count = i;
if (pr->power.states[i].type >= ACPI_STATE_C2) pr->flags.power = 1;
pr->flags.power = 1;
} }
} }
......
...@@ -28,9 +28,6 @@ ...@@ -28,9 +28,6 @@
#define ACPI_SBS_CLASS "sbs" #define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter" #define ACPI_AC_CLASS "ac_adapter"
#define ACPI_SBS_DEVICE_NAME "Smart Battery System" #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_BATTERY_DIR_NAME "BAT%i"
#define ACPI_AC_DIR_NAME "AC0" #define ACPI_AC_DIR_NAME "AC0"
......
...@@ -2157,10 +2157,13 @@ static void __init acpi_get_spcr_uart_addr(void) ...@@ -2157,10 +2157,13 @@ static void __init acpi_get_spcr_uart_addr(void)
status = acpi_get_table(ACPI_SIG_SPCR, 0, status = acpi_get_table(ACPI_SIG_SPCR, 0,
(struct acpi_table_header **)&spcr_ptr); (struct acpi_table_header **)&spcr_ptr);
if (ACPI_SUCCESS(status)) if (ACPI_FAILURE(status)) {
spcr_uart_addr = spcr_ptr->serial_port.address; pr_warn(PREFIX "STAO table present, but SPCR is missing\n");
else return;
printk(KERN_WARNING PREFIX "STAO table present, but SPCR is missing\n"); }
spcr_uart_addr = spcr_ptr->serial_port.address;
acpi_put_table((struct acpi_table_header *)spcr_ptr);
} }
static bool acpi_scan_initialized; static bool acpi_scan_initialized;
...@@ -2196,10 +2199,12 @@ int __init acpi_scan_init(void) ...@@ -2196,10 +2199,12 @@ int __init acpi_scan_init(void)
(struct acpi_table_header **)&stao_ptr); (struct acpi_table_header **)&stao_ptr);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
if (stao_ptr->header.length > sizeof(struct acpi_table_stao)) 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) if (stao_ptr->ignore_uart)
acpi_get_spcr_uart_addr(); acpi_get_spcr_uart_addr();
acpi_put_table((struct acpi_table_header *)stao_ptr);
} }
acpi_gpe_apply_masked_gpes(); acpi_gpe_apply_masked_gpes();
......
...@@ -1290,8 +1290,10 @@ static void acpi_sleep_hibernate_setup(void) ...@@ -1290,8 +1290,10 @@ static void acpi_sleep_hibernate_setup(void)
return; return;
acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs); acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
if (facs) if (facs) {
s4_hardware_signature = facs->hardware_signature; s4_hardware_signature = facs->hardware_signature;
acpi_put_table((struct acpi_table_header *)facs);
}
} }
#else /* !CONFIG_HIBERNATION */ #else /* !CONFIG_HIBERNATION */
static inline void acpi_sleep_hibernate_setup(void) {} static inline void acpi_sleep_hibernate_setup(void) {}
......
...@@ -993,8 +993,10 @@ void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, ...@@ -993,8 +993,10 @@ void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
error = kobject_init_and_add(&hotplug->kobj, error = kobject_init_and_add(&hotplug->kobj,
&acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name); &acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name);
if (error) if (error) {
kobject_put(&hotplug->kobj);
goto err_out; goto err_out;
}
kobject_uevent(&hotplug->kobj, KOBJ_ADD); kobject_uevent(&hotplug->kobj, KOBJ_ADD);
return; return;
......
...@@ -605,6 +605,31 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) ...@@ -605,6 +605,31 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
return status; return status;
} }
/**
* 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 * acpi_evaluate_dsm - evaluate device's _DSM method
* @handle: ACPI device handle * @handle: ACPI device handle
......
...@@ -361,6 +361,16 @@ static const struct dmi_system_id video_detect_dmi_table[] = { ...@@ -361,6 +361,16 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "JV50"), 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 * Desktops which falsely report a backlight and which our heuristics
......
...@@ -385,19 +385,12 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) ...@@ -385,19 +385,12 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
{ {
struct acpiphp_func *func; struct acpiphp_func *func;
union acpi_object params[2];
struct acpi_object_list arg_list;
list_for_each_entry(func, &slot->funcs, sibling) { 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 */ /* _REG is optional, we don't care about if there is failure */
acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list, acpi_evaluate_reg(func_to_handle(func),
NULL); ACPI_ADR_SPACE_PCI_CONFIG,
ACPI_REG_CONNECT);
} }
} }
......
...@@ -44,6 +44,7 @@ acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, ...@@ -44,6 +44,7 @@ acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
u64 arg); u64 arg);
acpi_status acpi_evaluate_ej0(acpi_handle handle); acpi_status acpi_evaluate_ej0(acpi_handle handle);
acpi_status acpi_evaluate_lck(acpi_handle handle, int lock); 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_ata_match(acpi_handle handle);
bool acpi_bay_match(acpi_handle handle); bool acpi_bay_match(acpi_handle handle);
bool acpi_dock_match(acpi_handle handle); bool acpi_dock_match(acpi_handle handle);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */ /* Current ACPICA subsystem version in YYYYMMDD format */
#define ACPI_CA_VERSION 0x20200326 #define ACPI_CA_VERSION 0x20200430
#include <acpi/acconfig.h> #include <acpi/acconfig.h>
#include <acpi/actypes.h> #include <acpi/actypes.h>
......
...@@ -33,6 +33,9 @@ struct ghes_estatus_node { ...@@ -33,6 +33,9 @@ struct ghes_estatus_node {
struct llist_node llnode; struct llist_node llnode;
struct acpi_hest_generic *generic; struct acpi_hest_generic *generic;
struct ghes *ghes; struct ghes *ghes;
int task_work_cpu;
struct callback_head task_work;
}; };
struct ghes_estatus_cache { struct ghes_estatus_cache {
......
...@@ -3048,6 +3048,7 @@ enum mf_flags { ...@@ -3048,6 +3048,7 @@ enum mf_flags {
}; };
extern int memory_failure(unsigned long pfn, int 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(unsigned long pfn, int flags);
extern void memory_failure_queue_kick(int cpu);
extern int unpoison_memory(unsigned long pfn); extern int unpoison_memory(unsigned long pfn);
extern int get_hwpoison_page(struct page *page); extern int get_hwpoison_page(struct page *page);
#define put_hwpoison_page(page) put_page(page) #define put_hwpoison_page(page) put_page(page)
......
...@@ -1496,7 +1496,7 @@ static void memory_failure_work_func(struct work_struct *work) ...@@ -1496,7 +1496,7 @@ static void memory_failure_work_func(struct work_struct *work)
unsigned long proc_flags; unsigned long proc_flags;
int gotten; int gotten;
mf_cpu = this_cpu_ptr(&memory_failure_cpu); mf_cpu = container_of(work, struct memory_failure_cpu, work);
for (;;) { for (;;) {
spin_lock_irqsave(&mf_cpu->lock, proc_flags); spin_lock_irqsave(&mf_cpu->lock, proc_flags);
gotten = kfifo_get(&mf_cpu->fifo, &entry); gotten = kfifo_get(&mf_cpu->fifo, &entry);
...@@ -1510,6 +1510,19 @@ static void memory_failure_work_func(struct work_struct *work) ...@@ -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) static int __init memory_failure_init(void)
{ {
struct memory_failure_cpu *mf_cpu; struct memory_failure_cpu *mf_cpu;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment