Merge branches 'acpi-pm', 'acpi-properties', 'acpi-misc' and 'acpi-x86'

Merge ACPI power management changes, ACPI device properties handling
changes, x86-specific ACPI changes and miscellaneous ACPI changes for
5.18-rc1:

 - Add power management debug messages related to suspend-to-idle in
   two places (Rafael Wysocki).

 - Fix __acpi_node_get_property_reference() return value and clean up
   that function (Andy Shevchenko, Sakari Ailus).

 - Fix return value of the __setup handler in the ACPI PM timer clock
   source driver (Randy Dunlap).

 - Clean up double words in two comments (Tom Rix).

 - Add "skip i2c clients" quirks for Lenovo Yoga Tablet 1050F/L and
   Nextbook Ares 8 (Hans de Goede).

 - Clean up frequency invariance handling on x86 in the ACPI CPPC
   library (Huang Rui).

 - Work around broken XSDT on the Advantech DAC-BJ01 board (Mark
   Cilissen).

* acpi-pm:
  ACPI: EC / PM: Print additional debug message in acpi_ec_dispatch_gpe()
  ACPI: PM: Print additional debug message in acpi_s2idle_wake()

* acpi-properties:
  ACPI: property: Get rid of redundant 'else'
  ACPI: properties: Consistently return -ENOENT if there are no more references

* acpi-misc:
  clocksource: acpi_pm: fix return value of __setup handler
  ACPI: clean up double words in two comments

* acpi-x86:
  ACPI / x86: Work around broken XSDT on Advantech DAC-BJ01 board
  x86/ACPI: CPPC: Move init_freq_invariance_cppc() into x86 CPPC
  x86: Expose init_freq_invariance() to topology header
  x86/ACPI: CPPC: Move AMD maximum frequency ratio setting function into x86 CPPC
  x86/ACPI: CPPC: Rename cppc_msr.c to cppc.c
  ACPI / x86: Add skip i2c clients quirk for Lenovo Yoga Tablet 1050F/L
  ACPI / x86: Add skip i2c clients quirk for Nextbook Ares 8
This commit is contained in:
Rafael J. Wysocki 2022-03-18 17:23:05 +01:00
13 changed files with 191 additions and 139 deletions

View File

@ -215,15 +215,26 @@ extern void arch_scale_freq_tick(void);
#define arch_scale_freq_tick arch_scale_freq_tick #define arch_scale_freq_tick arch_scale_freq_tick
extern void arch_set_max_freq_ratio(bool turbo_disabled); extern void arch_set_max_freq_ratio(bool turbo_disabled);
void init_freq_invariance(bool secondary, bool cppc_ready);
#else #else
static inline void arch_set_max_freq_ratio(bool turbo_disabled) static inline void arch_set_max_freq_ratio(bool turbo_disabled)
{ {
} }
static inline void init_freq_invariance(bool secondary, bool cppc_ready)
{
}
#endif #endif
#if defined(CONFIG_ACPI_CPPC_LIB) && defined(CONFIG_SMP) #ifdef CONFIG_ACPI_CPPC_LIB
void init_freq_invariance_cppc(void); void init_freq_invariance_cppc(void);
#define init_freq_invariance_cppc init_freq_invariance_cppc #define init_freq_invariance_cppc init_freq_invariance_cppc
bool amd_set_max_freq_ratio(u64 *ratio);
#else
static inline bool amd_set_max_freq_ratio(u64 *ratio)
{
return false;
}
#endif #endif
#endif /* _ASM_X86_TOPOLOGY_H */ #endif /* _ASM_X86_TOPOLOGY_H */

View File

@ -3,7 +3,7 @@
obj-$(CONFIG_ACPI) += boot.o obj-$(CONFIG_ACPI) += boot.o
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o
obj-$(CONFIG_ACPI_APEI) += apei.o obj-$(CONFIG_ACPI_APEI) += apei.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_msr.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
ifneq ($(CONFIG_ACPI_PROCESSOR),) ifneq ($(CONFIG_ACPI_PROCESSOR),)
obj-y += cstate.o obj-y += cstate.o

View File

@ -1328,6 +1328,17 @@ static int __init disable_acpi_pci(const struct dmi_system_id *d)
return 0; return 0;
} }
static int __init disable_acpi_xsdt(const struct dmi_system_id *d)
{
if (!acpi_force) {
pr_notice("%s detected: force use of acpi=rsdt\n", d->ident);
acpi_gbl_do_not_use_xsdt = TRUE;
} else {
pr_notice("Warning: DMI blacklist says broken, but acpi XSDT forced\n");
}
return 0;
}
static int __init dmi_disable_acpi(const struct dmi_system_id *d) static int __init dmi_disable_acpi(const struct dmi_system_id *d)
{ {
if (!acpi_force) { if (!acpi_force) {
@ -1451,6 +1462,19 @@ static const struct dmi_system_id acpi_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
}, },
}, },
/*
* Boxes that need ACPI XSDT use disabled due to corrupted tables
*/
{
.callback = disable_acpi_xsdt,
.ident = "Advantech DAC-BJ01",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "NEC"),
DMI_MATCH(DMI_PRODUCT_NAME, "Bearlake CRB Board"),
DMI_MATCH(DMI_BIOS_VERSION, "V1.12"),
DMI_MATCH(DMI_BIOS_DATE, "02/01/2011"),
},
},
{} {}
}; };

103
arch/x86/kernel/acpi/cppc.c Normal file
View File

@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* cppc.c: CPPC Interface for x86
* Copyright (c) 2016, Intel Corporation.
*/
#include <acpi/cppc_acpi.h>
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/topology.h>
/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
bool cpc_ffh_supported(void)
{
return true;
}
int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
{
int err;
err = rdmsrl_safe_on_cpu(cpunum, reg->address, val);
if (!err) {
u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
reg->bit_offset);
*val &= mask;
*val >>= reg->bit_offset;
}
return err;
}
int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
{
u64 rd_val;
int err;
err = rdmsrl_safe_on_cpu(cpunum, reg->address, &rd_val);
if (!err) {
u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
reg->bit_offset);
val <<= reg->bit_offset;
val &= mask;
rd_val &= ~mask;
rd_val |= val;
err = wrmsrl_safe_on_cpu(cpunum, reg->address, rd_val);
}
return err;
}
bool amd_set_max_freq_ratio(u64 *ratio)
{
struct cppc_perf_caps perf_caps;
u64 highest_perf, nominal_perf;
u64 perf_ratio;
int rc;
if (!ratio)
return false;
rc = cppc_get_perf_caps(0, &perf_caps);
if (rc) {
pr_debug("Could not retrieve perf counters (%d)\n", rc);
return false;
}
highest_perf = amd_get_highest_perf();
nominal_perf = perf_caps.nominal_perf;
if (!highest_perf || !nominal_perf) {
pr_debug("Could not retrieve highest or nominal performance\n");
return false;
}
perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf);
/* midpoint between max_boost and max_P */
perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1;
if (!perf_ratio) {
pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n");
return false;
}
*ratio = perf_ratio;
arch_set_max_freq_ratio(false);
return true;
}
static DEFINE_MUTEX(freq_invariance_lock);
void init_freq_invariance_cppc(void)
{
static bool secondary;
mutex_lock(&freq_invariance_lock);
init_freq_invariance(secondary, true);
secondary = true;
mutex_unlock(&freq_invariance_lock);
}

View File

@ -1,49 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* cppc_msr.c: MSR Interface for CPPC
* Copyright (c) 2016, Intel Corporation.
*/
#include <acpi/cppc_acpi.h>
#include <asm/msr.h>
/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
bool cpc_ffh_supported(void)
{
return true;
}
int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
{
int err;
err = rdmsrl_safe_on_cpu(cpunum, reg->address, val);
if (!err) {
u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
reg->bit_offset);
*val &= mask;
*val >>= reg->bit_offset;
}
return err;
}
int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
{
u64 rd_val;
int err;
err = rdmsrl_safe_on_cpu(cpunum, reg->address, &rd_val);
if (!err) {
u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
reg->bit_offset);
val <<= reg->bit_offset;
val &= mask;
rd_val &= ~mask;
rd_val |= val;
err = wrmsrl_safe_on_cpu(cpunum, reg->address, rd_val);
}
return err;
}

View File

@ -83,10 +83,6 @@
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/stackprotector.h> #include <asm/stackprotector.h>
#ifdef CONFIG_ACPI_CPPC_LIB
#include <acpi/cppc_acpi.h>
#endif
/* representing HT siblings of each logical CPU */ /* representing HT siblings of each logical CPU */
DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map); DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
@ -155,8 +151,6 @@ static inline void smpboot_restore_warm_reset_vector(void)
*((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0; *((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0;
} }
static void init_freq_invariance(bool secondary, bool cppc_ready);
/* /*
* Report back to the Boot Processor during boot time or to the caller processor * Report back to the Boot Processor during boot time or to the caller processor
* during CPU online. * during CPU online.
@ -2097,48 +2091,6 @@ out:
return true; return true;
} }
#ifdef CONFIG_ACPI_CPPC_LIB
static bool amd_set_max_freq_ratio(void)
{
struct cppc_perf_caps perf_caps;
u64 highest_perf, nominal_perf;
u64 perf_ratio;
int rc;
rc = cppc_get_perf_caps(0, &perf_caps);
if (rc) {
pr_debug("Could not retrieve perf counters (%d)\n", rc);
return false;
}
highest_perf = amd_get_highest_perf();
nominal_perf = perf_caps.nominal_perf;
if (!highest_perf || !nominal_perf) {
pr_debug("Could not retrieve highest or nominal performance\n");
return false;
}
perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf);
/* midpoint between max_boost and max_P */
perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1;
if (!perf_ratio) {
pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n");
return false;
}
arch_turbo_freq_ratio = perf_ratio;
arch_set_max_freq_ratio(false);
return true;
}
#else
static bool amd_set_max_freq_ratio(void)
{
return false;
}
#endif
static void init_counter_refs(void) static void init_counter_refs(void)
{ {
u64 aperf, mperf; u64 aperf, mperf;
@ -2167,7 +2119,7 @@ static void register_freq_invariance_syscore_ops(void)
static inline void register_freq_invariance_syscore_ops(void) {} static inline void register_freq_invariance_syscore_ops(void) {}
#endif #endif
static void init_freq_invariance(bool secondary, bool cppc_ready) void init_freq_invariance(bool secondary, bool cppc_ready)
{ {
bool ret = false; bool ret = false;
@ -2187,7 +2139,7 @@ static void init_freq_invariance(bool secondary, bool cppc_ready)
if (!cppc_ready) { if (!cppc_ready) {
return; return;
} }
ret = amd_set_max_freq_ratio(); ret = amd_set_max_freq_ratio(&arch_turbo_freq_ratio);
} }
if (ret) { if (ret) {
@ -2200,22 +2152,6 @@ static void init_freq_invariance(bool secondary, bool cppc_ready)
} }
} }
#ifdef CONFIG_ACPI_CPPC_LIB
static DEFINE_MUTEX(freq_invariance_lock);
void init_freq_invariance_cppc(void)
{
static bool secondary;
mutex_lock(&freq_invariance_lock);
init_freq_invariance(secondary, true);
secondary = true;
mutex_unlock(&freq_invariance_lock);
}
#endif
static void disable_freq_invariance_workfn(struct work_struct *work) static void disable_freq_invariance_workfn(struct work_struct *work)
{ {
static_branch_disable(&arch_scale_freq_key); static_branch_disable(&arch_scale_freq_key);
@ -2264,8 +2200,4 @@ error:
pr_warn("Scheduler frequency invariance went wobbly, disabling!\n"); pr_warn("Scheduler frequency invariance went wobbly, disabling!\n");
schedule_work(&disable_freq_invariance_work); schedule_work(&disable_freq_invariance_work);
} }
#else
static inline void init_freq_invariance(bool secondary, bool cppc_ready)
{
}
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */

View File

@ -302,7 +302,7 @@ config ACPI_IPMI
help help
This driver enables the ACPI to access the BMC controller. And it This driver enables the ACPI to access the BMC controller. And it
uses the IPMI request/response message to communicate with BMC uses the IPMI request/response message to communicate with BMC
controller, which can be found on on the server. controller, which can be found on the server.
To compile this driver as a module, choose M here: To compile this driver as a module, choose M here:
the module will be called as acpi_ipmi. the module will be called as acpi_ipmi.

View File

@ -2081,8 +2081,11 @@ bool acpi_ec_dispatch_gpe(void)
*/ */
spin_lock_irq(&first_ec->lock); spin_lock_irq(&first_ec->lock);
if (acpi_ec_gpe_status_set(first_ec)) if (acpi_ec_gpe_status_set(first_ec)) {
pm_pr_dbg("ACPI EC GPE status set\n");
work_in_progress = advance_transaction(first_ec, false); work_in_progress = advance_transaction(first_ec, false);
}
spin_unlock_irq(&first_ec->lock); spin_unlock_irq(&first_ec->lock);

View File

@ -185,7 +185,7 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
if (!p || !p->interrupt_count) { if (!p || !p->interrupt_count) {
/* /*
* IRQ descriptors may have no IRQ# bits set, * IRQ descriptors may have no IRQ# bits set,
* particularly those those w/ _STA disabled * particularly those w/ _STA disabled
*/ */
pr_debug("Blank _CRS IRQ resource\n"); pr_debug("Blank _CRS IRQ resource\n");
return AE_OK; return AE_OK;

View File

@ -541,7 +541,8 @@ acpi_device_data_of_node(const struct fwnode_handle *fwnode)
if (is_acpi_device_node(fwnode)) { if (is_acpi_device_node(fwnode)) {
const struct acpi_device *adev = to_acpi_device_node(fwnode); const struct acpi_device *adev = to_acpi_device_node(fwnode);
return &adev->data; return &adev->data;
} else if (is_acpi_data_node(fwnode)) { }
if (is_acpi_data_node(fwnode)) {
const struct acpi_data_node *dn = to_acpi_data_node(fwnode); const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
return &dn->data; return &dn->data;
} }
@ -685,7 +686,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
*/ */
if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) { if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
if (index) if (index)
return -EINVAL; return -ENOENT;
device = acpi_fetch_acpi_dev(obj->reference.handle); device = acpi_fetch_acpi_dev(obj->reference.handle);
if (!device) if (!device)
@ -739,14 +740,19 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
return -EINVAL; return -EINVAL;
} }
/* assume following integer elements are all args */ /*
* Assume the following integer elements are all args.
* Stop counting on the first reference or end of the
* package arguments. In case of neither reference,
* nor integer, return an error, we can't parse it.
*/
for (i = 0; element + i < end && i < num_args; i++) { for (i = 0; element + i < end && i < num_args; i++) {
int type = element[i].type; int type = element[i].type;
if (type == ACPI_TYPE_LOCAL_REFERENCE)
break;
if (type == ACPI_TYPE_INTEGER) if (type == ACPI_TYPE_INTEGER)
nargs++; nargs++;
else if (type == ACPI_TYPE_LOCAL_REFERENCE)
break;
else else
return -EINVAL; return -EINVAL;
} }
@ -950,7 +956,7 @@ static int acpi_data_prop_read(const struct acpi_device_data *data,
if (proptype != DEV_PROP_STRING && nval > obj->package.count) if (proptype != DEV_PROP_STRING && nval > obj->package.count)
return -EOVERFLOW; return -EOVERFLOW;
else if (nval <= 0) if (nval == 0)
return -EINVAL; return -EINVAL;
items = obj->package.elements; items = obj->package.elements;
@ -1012,14 +1018,10 @@ struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
const struct list_head *head; const struct list_head *head;
struct list_head *next; struct list_head *next;
if (!child || is_acpi_device_node(child)) { if ((!child || is_acpi_device_node(child)) && adev) {
struct acpi_device *child_adev; struct acpi_device *child_adev;
if (adev) head = &adev->children;
head = &adev->children;
else
goto nondev;
if (list_empty(head)) if (list_empty(head))
goto nondev; goto nondev;
@ -1089,7 +1091,8 @@ acpi_node_get_parent(const struct fwnode_handle *fwnode)
if (is_acpi_data_node(fwnode)) { if (is_acpi_data_node(fwnode)) {
/* All data nodes have parent pointer so just return that */ /* All data nodes have parent pointer so just return that */
return to_acpi_data_node(fwnode)->parent; return to_acpi_data_node(fwnode)->parent;
} else if (is_acpi_device_node(fwnode)) { }
if (is_acpi_device_node(fwnode)) {
struct device *dev = to_acpi_device_node(fwnode)->dev.parent; struct device *dev = to_acpi_device_node(fwnode)->dev.parent;
if (dev) if (dev)

View File

@ -758,6 +758,8 @@ bool acpi_s2idle_wake(void)
return true; return true;
} }
pm_pr_dbg("Rearming ACPI SCI for wakeup\n");
pm_wakeup_clear(acpi_sci_irq); pm_wakeup_clear(acpi_sci_irq);
rearm_wake_irq(acpi_sci_irq); rearm_wake_irq(acpi_sci_irq);
} }

View File

@ -284,6 +284,27 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY), ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
}, },
{
/* Lenovo Yoga Tablet 1050F/L */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
/* Partial match on beginning of BIOS version */
DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
},
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
},
{
/* Nextbook Ares 8 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
DMI_MATCH(DMI_PRODUCT_NAME, "M890BAP"),
},
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
},
{ {
/* Whitelabel (sold as various brands) TM800A550L */ /* Whitelabel (sold as various brands) TM800A550L */
.matches = { .matches = {

View File

@ -229,8 +229,10 @@ static int __init parse_pmtmr(char *arg)
int ret; int ret;
ret = kstrtouint(arg, 16, &base); ret = kstrtouint(arg, 16, &base);
if (ret) if (ret) {
return ret; pr_warn("PMTMR: invalid 'pmtmr=' value: '%s'\n", arg);
return 1;
}
pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport, pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport,
base); base);