ACPI support updates for 6.19-rc1
- Avoid walking the ACPI namespace in the AML interpreter if the
starting node cannot be determined (Cryolitia PukNgae)
- Use min() instead of min_t() in the ACPI device properties handling
code to avoid discarding significant bits (David Laight)
- Fix potential fwnode refcount leak in acpi_fwnode_graph_parse_endpoint()
that may prevent the parent fwnode from being released (Haotian Zhang)
- Rework acpi_graph_get_next_endpoint() to use ACPI functions only, remove
unnecessary conditionals from it to make it easier to follow, and make
acpi_get_next_subnode() static (Sakari Ailus)
- Drop unused function acpi_get_lps0_constraint(), make some Low-Power
S0 callback functions for suspend-to-idle static, and rearrange the
code retrieving Low-Power S0 constraints so it only runs when the
constraints are actually used (Rafael Wysocki)
- Drop redundant locking from the ACPI battery driver (Rafael Wysocki)
- Improve runtime PM in the ACPI time and alarm device (TAD) driver
using guard macros and rearrange code related to runtime PM in
acpi_tad_remove() (Rafael Wysocki)
- Add support for Microsoft fan extensions to the ACPI fan driver along
with notification support and work around a 64-bit firmware bug in
that driver (Armin Wolf)
- Use ACPI_FREE() to free ACPI buffer in the ACPI DPTF code (Kaushlendra
Kumar)
- Fix a memory leak and a resource leak in the ACPI pfrut utility (Malaya
Kumar Rout)
- Replace `core::mem::zeroed` with `pin_init::zeroed` in the ACPI Rust
code (Siyuan Huang)
- Update the ACPI code to use the new style of allocating workqueues
and new global workqueues (Marco Crivellari)
- Fix two spelling mistakes in the ACPI code (Chu Guangqing)
- Fix ISAPNP to generate uevents to auto-load modules (René Rebe)
- Relocate the state flags initialization in the ACPI processor idle
driver and drop redundant C-state count checks from it (Huisong Li)
- Fix map_x2apic_id() in the ACPI processor core driver for amd-pstate
on am4 (René Rebe)
-----BEGIN PGP SIGNATURE-----
iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmkpsnISHHJqd0Byand5
c29ja2kubmV0AAoJEO5fvZ0v1OO1OoAH/0hw86dPEF2hj1Pw06/o2pS4+Ka/yCAm
vSRn0WOyCEVPWzFmNWg6bZCgUC8AmFRkqXlafI2q9SCcgUaoG8dQ1sWijAEe4Pdz
eo5G1pnDiNiljAF9JYUCtkAmmEZo7k9aQovi3RIhyS+rOdrLjCGziz5sbzalj2hJ
CF6w3rN5O5Cp9lf3zPFF90AZsg9WuPVGa1xr2CjaNbrTuSwbmQn73X6JHuc8ROSX
aeAIwvtSNIqdyBFLx52hdM9g7M+cm0UMe6eLMCtVTu4wOw1kL/QHNklzETTv6Fce
P2JihZDhClaT2CKA4k/6vD4BQaPtTDvMFOV8TUM4rbmTw0hpxzKgLTc=
=P5HW
-----END PGP SIGNATURE-----
Merge tag 'acpi-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI updates from Rafael Wysocki:
"These add Microsoft fan extensions support to the ACPI fan driver, fix
a bug in ACPICA, update other ACPI drivers (processor, time and alarm
device), update ACPI power management code and ACPI device properties
management, and fix an ACPI utility:
- Avoid walking the ACPI namespace in the AML interpreter if the
starting node cannot be determined (Cryolitia PukNgae)
- Use min() instead of min_t() in the ACPI device properties handling
code to avoid discarding significant bits (David Laight)
- Fix potential fwnode refcount leak in
acpi_fwnode_graph_parse_endpoint() that may prevent the parent
fwnode from being released (Haotian Zhang)
- Rework acpi_graph_get_next_endpoint() to use ACPI functions only,
remove unnecessary conditionals from it to make it easier to
follow, and make acpi_get_next_subnode() static (Sakari Ailus)
- Drop unused function acpi_get_lps0_constraint(), make some
Low-Power S0 callback functions for suspend-to-idle static, and
rearrange the code retrieving Low-Power S0 constraints so it only
runs when the constraints are actually used (Rafael Wysocki)
- Drop redundant locking from the ACPI battery driver (Rafael
Wysocki)
- Improve runtime PM in the ACPI time and alarm device (TAD) driver
using guard macros and rearrange code related to runtime PM in
acpi_tad_remove() (Rafael Wysocki)
- Add support for Microsoft fan extensions to the ACPI fan driver
along with notification support and work around a 64-bit firmware
bug in that driver (Armin Wolf)
- Use ACPI_FREE() to free ACPI buffer in the ACPI DPTF code
(Kaushlendra Kumar)
- Fix a memory leak and a resource leak in the ACPI pfrut utility
(Malaya Kumar Rout)
- Replace `core::mem::zeroed` with `pin_init::zeroed` in the ACPI
Rust code (Siyuan Huang)
- Update the ACPI code to use the new style of allocating workqueues
and new global workqueues (Marco Crivellari)
- Fix two spelling mistakes in the ACPI code (Chu Guangqing)
- Fix ISAPNP to generate uevents to auto-load modules (René Rebe)
- Relocate the state flags initialization in the ACPI processor idle
driver and drop redundant C-state count checks from it (Huisong Li)
- Fix map_x2apic_id() in the ACPI processor core driver for
amd-pstate on am4 (René Rebe)"
* tag 'acpi-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (30 commits)
ACPI: PM: Fix a spelling mistake
ACPI: LPSS: Fix a spelling mistake
ACPI: processor_core: fix map_x2apic_id for amd-pstate on am4
ACPICA: Avoid walking the Namespace if start_node is NULL
ACPI: tools: pfrut: fix memory leak and resource leak in pfrut.c
ACPI: property: use min() instead of min_t()
PNP: Fix ISAPNP to generate uevents to auto-load modules
ACPI: property: Fix fwnode refcount leak in acpi_fwnode_graph_parse_endpoint()
ACPI: DPTF: Use ACPI_FREE() for ACPI buffer deallocation
ACPI: processor: idle: Drop redundant C-state count checks
ACPI: thermal: Add WQ_PERCPU to alloc_workqueue() users
ACPI: OSL: Add WQ_PERCPU to alloc_workqueue() users
ACPI: EC: Add WQ_PERCPU to alloc_workqueue() users
ACPI: OSL: replace use of system_wq with system_percpu_wq
ACPI: scan: replace use of system_unbound_wq with system_dfl_wq
ACPI: fan: Add support for Microsoft fan extensions
ACPI: fan: Add hwmon notification support
ACPI: fan: Add basic notification support
ACPI: TAD: Improve runtime PM using guard macros
ACPI: TAD: Rearrange runtime PM operations in acpi_tad_remove()
...
pull/1354/merge
commit
959bfe496b
|
|
@ -90,19 +90,18 @@ static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
|
|||
args[0].buffer.pointer = (u8 *)rt;
|
||||
args[0].buffer.length = sizeof(*rt);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
ACQUIRE(pm_runtime_active_try, pm)(dev);
|
||||
if (ACQUIRE_ERR(pm_runtime_active_try, &pm))
|
||||
return -ENXIO;
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
if (ACPI_FAILURE(status) || retval)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
|
||||
static int acpi_tad_evaluate_grt(struct device *dev, struct acpi_tad_rt *rt)
|
||||
{
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER };
|
||||
|
|
@ -111,12 +110,7 @@ static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
|
|||
acpi_status status;
|
||||
int ret = -EIO;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
status = acpi_evaluate_object(handle, "_GRT", NULL, &output);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
goto out_free;
|
||||
|
||||
|
|
@ -139,6 +133,21 @@ out_free:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ACQUIRE(pm_runtime_active_try, pm)(dev);
|
||||
if (ACQUIRE_ERR(pm_runtime_active_try, &pm))
|
||||
return -ENXIO;
|
||||
|
||||
ret = acpi_tad_evaluate_grt(dev, rt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *acpi_tad_rt_next_field(char *s, int *val)
|
||||
{
|
||||
char *p;
|
||||
|
|
@ -266,12 +275,11 @@ static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
|
|||
args[0].integer.value = timer_id;
|
||||
args[1].integer.value = value;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
ACQUIRE(pm_runtime_active_try, pm)(dev);
|
||||
if (ACQUIRE_ERR(pm_runtime_active_try, &pm))
|
||||
return -ENXIO;
|
||||
|
||||
status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
if (ACPI_FAILURE(status) || retval)
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -314,12 +322,11 @@ static ssize_t acpi_tad_wake_read(struct device *dev, char *buf, char *method,
|
|||
|
||||
args[0].integer.value = timer_id;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
ACQUIRE(pm_runtime_active_try, pm)(dev);
|
||||
if (ACQUIRE_ERR(pm_runtime_active_try, &pm))
|
||||
return -ENXIO;
|
||||
|
||||
status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -370,12 +377,11 @@ static int acpi_tad_clear_status(struct device *dev, u32 timer_id)
|
|||
|
||||
args[0].integer.value = timer_id;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
ACQUIRE(pm_runtime_active_try, pm)(dev);
|
||||
if (ACQUIRE_ERR(pm_runtime_active_try, &pm))
|
||||
return -ENXIO;
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_CWS", &arg_list, &retval);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
if (ACPI_FAILURE(status) || retval)
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -411,12 +417,11 @@ static ssize_t acpi_tad_status_read(struct device *dev, char *buf, u32 timer_id)
|
|||
|
||||
args[0].integer.value = timer_id;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
ACQUIRE(pm_runtime_active_try, pm)(dev);
|
||||
if (ACQUIRE_ERR(pm_runtime_active_try, &pm))
|
||||
return -ENXIO;
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_GWS", &arg_list, &retval);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -563,8 +568,6 @@ static void acpi_tad_remove(struct platform_device *pdev)
|
|||
|
||||
device_init_wakeup(dev, false);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
if (dd->capabilities & ACPI_TAD_RT)
|
||||
sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group);
|
||||
|
||||
|
|
@ -573,14 +576,16 @@ static void acpi_tad_remove(struct platform_device *pdev)
|
|||
|
||||
sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group);
|
||||
|
||||
acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
|
||||
acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
|
||||
if (dd->capabilities & ACPI_TAD_DC_WAKE) {
|
||||
acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER);
|
||||
acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER);
|
||||
scoped_guard(pm_runtime_noresume, dev) {
|
||||
acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
|
||||
acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
|
||||
if (dd->capabilities & ACPI_TAD_DC_WAKE) {
|
||||
acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER);
|
||||
acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_suspend(dev);
|
||||
pm_runtime_disable(dev);
|
||||
acpi_remove_cmos_rtc_space_handler(handle);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,9 +169,12 @@ acpi_ns_walk_namespace(acpi_object_type type,
|
|||
|
||||
if (start_node == ACPI_ROOT_OBJECT) {
|
||||
start_node = acpi_gbl_root_node;
|
||||
if (!start_node) {
|
||||
return_ACPI_STATUS(AE_NO_NAMESPACE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Avoid walking the namespace if the StartNode is NULL */
|
||||
|
||||
if (!start_node) {
|
||||
return_ACPI_STATUS(AE_NO_NAMESPACE);
|
||||
}
|
||||
|
||||
/* Null child means "get first node" */
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ enum {
|
|||
};
|
||||
|
||||
struct acpi_battery {
|
||||
struct mutex lock;
|
||||
struct mutex update_lock;
|
||||
struct power_supply *bat;
|
||||
struct power_supply_desc bat_desc;
|
||||
|
|
@ -535,11 +534,9 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
|
|||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_status status = AE_ERROR;
|
||||
|
||||
mutex_lock(&battery->lock);
|
||||
status = acpi_evaluate_object(battery->device->handle,
|
||||
use_bix ? "_BIX":"_BIF",
|
||||
NULL, &buffer);
|
||||
mutex_unlock(&battery->lock);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_handle_info(battery->device->handle,
|
||||
|
|
@ -576,11 +573,8 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
|
|||
msecs_to_jiffies(cache_time)))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&battery->lock);
|
||||
status = acpi_evaluate_object(battery->device->handle, "_BST",
|
||||
NULL, &buffer);
|
||||
mutex_unlock(&battery->lock);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_handle_info(battery->device->handle,
|
||||
"_BST evaluation failed: %s",
|
||||
|
|
@ -628,11 +622,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery)
|
|||
!test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&battery->lock);
|
||||
status = acpi_execute_simple_method(battery->device->handle, "_BTP",
|
||||
battery->alarm);
|
||||
mutex_unlock(&battery->lock);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
|
|
@ -1235,9 +1226,6 @@ static int acpi_battery_add(struct acpi_device *device)
|
|||
strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
|
||||
strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
|
||||
device->driver_data = battery;
|
||||
result = devm_mutex_init(&device->dev, &battery->lock);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = devm_mutex_init(&device->dev, &battery->update_lock);
|
||||
if (result)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ static int pch_fivr_read(acpi_handle handle, char *method, struct pch_fivr_resp
|
|||
ret = 0;
|
||||
|
||||
release_buffer:
|
||||
kfree(buffer.pointer);
|
||||
ACPI_FREE(buffer.pointer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2294,7 +2294,8 @@ static int acpi_ec_init_workqueues(void)
|
|||
ec_wq = alloc_ordered_workqueue("kec", 0);
|
||||
|
||||
if (!ec_query_wq)
|
||||
ec_query_wq = alloc_workqueue("kec_query", 0, ec_max_queries);
|
||||
ec_query_wq = alloc_workqueue("kec_query", WQ_PERCPU,
|
||||
ec_max_queries);
|
||||
|
||||
if (!ec_wq || !ec_query_wq) {
|
||||
acpi_ec_destroy_workqueues();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#define _ACPI_FAN_H_
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#define ACPI_FAN_DEVICE_IDS \
|
||||
{"INT3404", }, /* Fan */ \
|
||||
|
|
@ -55,19 +56,58 @@ struct acpi_fan {
|
|||
struct acpi_fan_fif fif;
|
||||
struct acpi_fan_fps *fps;
|
||||
int fps_count;
|
||||
/* A value of 0 means that trippoint-related functions are not supported */
|
||||
u32 fan_trip_granularity;
|
||||
#if IS_REACHABLE(CONFIG_HWMON)
|
||||
struct device *hdev;
|
||||
#endif
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct device_attribute fst_speed;
|
||||
struct device_attribute fine_grain_control;
|
||||
};
|
||||
|
||||
/**
|
||||
* acpi_fan_speed_valid - Check if fan speed value is valid
|
||||
* @speeed: Speed value returned by the ACPI firmware
|
||||
*
|
||||
* Check if the fan speed value returned by the ACPI firmware is valid. This function is
|
||||
* necessary as ACPI firmware implementations can return 0xFFFFFFFF to signal that the
|
||||
* ACPI fan does not support speed reporting. Additionally, some buggy ACPI firmware
|
||||
* implementations return a value larger than the 32-bit integer value defined by
|
||||
* the ACPI specification when using placeholder values. Such invalid values are also
|
||||
* detected by this function.
|
||||
*
|
||||
* Returns: True if the fan speed value is valid, false otherwise.
|
||||
*/
|
||||
static inline bool acpi_fan_speed_valid(u64 speed)
|
||||
{
|
||||
return speed < U32_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_fan_power_valid - Check if fan power value is valid
|
||||
* @power: Power value returned by the ACPI firmware
|
||||
*
|
||||
* Check if the fan power value returned by the ACPI firmware is valid.
|
||||
* See acpi_fan_speed_valid() for details.
|
||||
*
|
||||
* Returns: True if the fan power value is valid, false otherwise.
|
||||
*/
|
||||
static inline bool acpi_fan_power_valid(u64 power)
|
||||
{
|
||||
return power < U32_MAX;
|
||||
}
|
||||
|
||||
int acpi_fan_get_fst(acpi_handle handle, struct acpi_fan_fst *fst);
|
||||
int acpi_fan_create_attributes(struct acpi_device *device);
|
||||
void acpi_fan_delete_attributes(struct acpi_device *device);
|
||||
|
||||
#if IS_REACHABLE(CONFIG_HWMON)
|
||||
int devm_acpi_fan_create_hwmon(struct device *dev);
|
||||
void acpi_fan_notify_hwmon(struct device *dev);
|
||||
#else
|
||||
static inline int devm_acpi_fan_create_hwmon(struct device *dev) { return 0; };
|
||||
static inline void acpi_fan_notify_hwmon(struct device *dev) { };
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,11 +7,16 @@
|
|||
* Copyright (C) 2022 Intel Corporation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -19,6 +24,26 @@
|
|||
|
||||
#include "fan.h"
|
||||
|
||||
#define ACPI_FAN_NOTIFY_STATE_CHANGED 0x80
|
||||
|
||||
/*
|
||||
* Defined inside the "Fan Noise Signal" section at
|
||||
* https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/design-guide.
|
||||
*/
|
||||
static const guid_t acpi_fan_microsoft_guid = GUID_INIT(0xA7611840, 0x99FE, 0x41AE, 0xA4, 0x88,
|
||||
0x35, 0xC7, 0x59, 0x26, 0xC8, 0xEB);
|
||||
#define ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY 1
|
||||
#define ACPI_FAN_DSM_SET_TRIP_POINTS 2
|
||||
#define ACPI_FAN_DSM_GET_OPERATING_RANGES 3
|
||||
|
||||
/*
|
||||
* Ensures that fans with a very low trip point granularity
|
||||
* do not send too many notifications.
|
||||
*/
|
||||
static uint min_trip_distance = 100;
|
||||
module_param(min_trip_distance, uint, 0);
|
||||
MODULE_PARM_DESC(min_trip_distance, "Minimum distance between fan speed trip points in RPM");
|
||||
|
||||
static const struct acpi_device_id fan_device_ids[] = {
|
||||
ACPI_FAN_DEVICE_IDS,
|
||||
{"", 0},
|
||||
|
|
@ -308,6 +333,182 @@ err:
|
|||
return status;
|
||||
}
|
||||
|
||||
static int acpi_fan_dsm_init(struct device *dev)
|
||||
{
|
||||
union acpi_object dummy = {
|
||||
.package = {
|
||||
.type = ACPI_TYPE_PACKAGE,
|
||||
.count = 0,
|
||||
.elements = NULL,
|
||||
},
|
||||
};
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
union acpi_object *obj;
|
||||
int ret = 0;
|
||||
|
||||
if (!acpi_check_dsm(fan->handle, &acpi_fan_microsoft_guid, 0,
|
||||
BIT(ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY) |
|
||||
BIT(ACPI_FAN_DSM_SET_TRIP_POINTS)))
|
||||
return 0;
|
||||
|
||||
dev_info(dev, "Using Microsoft fan extensions\n");
|
||||
|
||||
obj = acpi_evaluate_dsm_typed(fan->handle, &acpi_fan_microsoft_guid, 0,
|
||||
ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY, &dummy,
|
||||
ACPI_TYPE_INTEGER);
|
||||
if (!obj)
|
||||
return -EIO;
|
||||
|
||||
if (obj->integer.value > U32_MAX)
|
||||
ret = -EOVERFLOW;
|
||||
else
|
||||
fan->fan_trip_granularity = obj->integer.value;
|
||||
|
||||
kfree(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_fan_dsm_set_trip_points(struct device *dev, u64 upper, u64 lower)
|
||||
{
|
||||
union acpi_object args[2] = {
|
||||
{
|
||||
.integer = {
|
||||
.type = ACPI_TYPE_INTEGER,
|
||||
.value = lower,
|
||||
},
|
||||
},
|
||||
{
|
||||
.integer = {
|
||||
.type = ACPI_TYPE_INTEGER,
|
||||
.value = upper,
|
||||
},
|
||||
},
|
||||
};
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
union acpi_object in = {
|
||||
.package = {
|
||||
.type = ACPI_TYPE_PACKAGE,
|
||||
.count = ARRAY_SIZE(args),
|
||||
.elements = args,
|
||||
},
|
||||
};
|
||||
union acpi_object *obj;
|
||||
|
||||
obj = acpi_evaluate_dsm(fan->handle, &acpi_fan_microsoft_guid, 0,
|
||||
ACPI_FAN_DSM_SET_TRIP_POINTS, &in);
|
||||
kfree(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_fan_dsm_start(struct device *dev)
|
||||
{
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (!fan->fan_trip_granularity)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Some firmware implementations only update the values returned by the
|
||||
* _FST control method when a notification is received. This usually
|
||||
* works with Microsoft Windows as setting up trip points will keep
|
||||
* triggering said notifications, but will cause issues when using _FST
|
||||
* without the Microsoft-specific trip point extension.
|
||||
*
|
||||
* Because of this, an initial notification needs to be triggered to
|
||||
* start the cycle of trip points updates. This is achieved by setting
|
||||
* the trip points sequencially to two separate ranges. As by the
|
||||
* Microsoft specification the firmware should trigger a notification
|
||||
* immediately if the fan speed is outside the trip point range. This
|
||||
* _should_ result in at least one notification as both ranges do not
|
||||
* overlap, meaning that the current fan speed needs to be outside at
|
||||
* least one range.
|
||||
*/
|
||||
ret = acpi_fan_dsm_set_trip_points(dev, fan->fan_trip_granularity, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return acpi_fan_dsm_set_trip_points(dev, fan->fan_trip_granularity * 3,
|
||||
fan->fan_trip_granularity * 2);
|
||||
}
|
||||
|
||||
static int acpi_fan_dsm_update_trips_points(struct device *dev, struct acpi_fan_fst *fst)
|
||||
{
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
u64 upper, lower;
|
||||
|
||||
if (!fan->fan_trip_granularity)
|
||||
return 0;
|
||||
|
||||
if (!acpi_fan_speed_valid(fst->speed))
|
||||
return -EINVAL;
|
||||
|
||||
upper = roundup_u64(fst->speed + min_trip_distance, fan->fan_trip_granularity);
|
||||
if (fst->speed <= min_trip_distance) {
|
||||
lower = 0;
|
||||
} else {
|
||||
/*
|
||||
* Valid fan speed values cannot be larger than 32 bit, so
|
||||
* we can safely assume that no overflow will happen here.
|
||||
*/
|
||||
lower = rounddown((u32)fst->speed - min_trip_distance, fan->fan_trip_granularity);
|
||||
}
|
||||
|
||||
return acpi_fan_dsm_set_trip_points(dev, upper, lower);
|
||||
}
|
||||
|
||||
static void acpi_fan_notify_handler(acpi_handle handle, u32 event, void *context)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct acpi_fan_fst fst;
|
||||
int ret;
|
||||
|
||||
switch (event) {
|
||||
case ACPI_FAN_NOTIFY_STATE_CHANGED:
|
||||
/*
|
||||
* The ACPI specification says that we must evaluate _FST when we
|
||||
* receive an ACPI event indicating that the fan state has changed.
|
||||
*/
|
||||
ret = acpi_fan_get_fst(handle, &fst);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error retrieving current fan status: %d\n", ret);
|
||||
} else {
|
||||
ret = acpi_fan_dsm_update_trips_points(dev, &fst);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to update trip points: %d\n", ret);
|
||||
}
|
||||
|
||||
acpi_fan_notify_hwmon(dev);
|
||||
acpi_bus_generate_netlink_event("fan", dev_name(dev), event, 0);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "Unsupported ACPI notification 0x%x\n", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_fan_notify_remove(void *data)
|
||||
{
|
||||
struct acpi_fan *fan = data;
|
||||
|
||||
acpi_remove_notify_handler(fan->handle, ACPI_DEVICE_NOTIFY, acpi_fan_notify_handler);
|
||||
}
|
||||
|
||||
static int devm_acpi_fan_notify_init(struct device *dev)
|
||||
{
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_install_notify_handler(fan->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_fan_notify_handler, dev);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
return devm_add_action_or_reset(dev, acpi_fan_notify_remove, fan);
|
||||
}
|
||||
|
||||
static int acpi_fan_probe(struct platform_device *pdev)
|
||||
{
|
||||
int result = 0;
|
||||
|
|
@ -347,10 +548,24 @@ static int acpi_fan_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (fan->has_fst) {
|
||||
result = acpi_fan_dsm_init(&pdev->dev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = devm_acpi_fan_create_hwmon(&pdev->dev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = devm_acpi_fan_notify_init(&pdev->dev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = acpi_fan_dsm_start(&pdev->dev);
|
||||
if (result) {
|
||||
dev_err(&pdev->dev, "Failed to start Microsoft fan extensions\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
result = acpi_fan_create_attributes(device);
|
||||
if (result)
|
||||
return result;
|
||||
|
|
@ -436,8 +651,14 @@ static int acpi_fan_suspend(struct device *dev)
|
|||
|
||||
static int acpi_fan_resume(struct device *dev)
|
||||
{
|
||||
int result;
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
int result;
|
||||
|
||||
if (fan->has_fst) {
|
||||
result = acpi_fan_dsm_start(dev);
|
||||
if (result)
|
||||
dev_err(dev, "Failed to start Microsoft fan extensions: %d\n", result);
|
||||
}
|
||||
|
||||
if (fan->acpi4)
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@
|
|||
|
||||
#include "fan.h"
|
||||
|
||||
/* Returned when the ACPI fan does not support speed reporting */
|
||||
#define FAN_SPEED_UNAVAILABLE U32_MAX
|
||||
#define FAN_POWER_UNAVAILABLE U32_MAX
|
||||
|
||||
static struct acpi_fan_fps *acpi_fan_get_current_fps(struct acpi_fan *fan, u64 control)
|
||||
{
|
||||
unsigned int i;
|
||||
|
|
@ -77,7 +73,7 @@ static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_
|
|||
* when the associated attribute should not be created.
|
||||
*/
|
||||
for (i = 0; i < fan->fps_count; i++) {
|
||||
if (fan->fps[i].power != FAN_POWER_UNAVAILABLE)
|
||||
if (acpi_fan_power_valid(fan->fps[i].power))
|
||||
return 0444;
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +102,7 @@ static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
if (fst.speed == FAN_SPEED_UNAVAILABLE)
|
||||
if (!acpi_fan_speed_valid(fst.speed))
|
||||
return -ENODEV;
|
||||
|
||||
if (fst.speed > LONG_MAX)
|
||||
|
|
@ -134,7 +130,7 @@ static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
if (!fps)
|
||||
return -EIO;
|
||||
|
||||
if (fps->power == FAN_POWER_UNAVAILABLE)
|
||||
if (!acpi_fan_power_valid(fps->power))
|
||||
return -ENODEV;
|
||||
|
||||
if (fps->power > LONG_MAX / MICROWATT_PER_MILLIWATT)
|
||||
|
|
@ -166,12 +162,19 @@ static const struct hwmon_chip_info acpi_fan_hwmon_chip_info = {
|
|||
.info = acpi_fan_hwmon_info,
|
||||
};
|
||||
|
||||
void acpi_fan_notify_hwmon(struct device *dev)
|
||||
{
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
|
||||
hwmon_notify_event(fan->hdev, hwmon_fan, hwmon_fan_input, 0);
|
||||
}
|
||||
|
||||
int devm_acpi_fan_create_hwmon(struct device *dev)
|
||||
{
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
struct device *hdev;
|
||||
|
||||
hdev = devm_hwmon_device_register_with_info(dev, "acpi_fan", fan, &acpi_fan_hwmon_chip_info,
|
||||
NULL);
|
||||
return PTR_ERR_OR_ZERO(hdev);
|
||||
fan->hdev = devm_hwmon_device_register_with_info(dev, "acpi_fan", fan,
|
||||
&acpi_fan_hwmon_chip_info, NULL);
|
||||
|
||||
return PTR_ERR_OR_ZERO(fan->hdev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
|
|||
list_del_rcu(&map->list);
|
||||
|
||||
INIT_RCU_WORK(&map->track.rwork, acpi_os_map_remove);
|
||||
queue_rcu_work(system_wq, &map->track.rwork);
|
||||
queue_rcu_work(system_percpu_wq, &map->track.rwork);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1694,8 +1694,8 @@ acpi_status __init acpi_os_initialize(void)
|
|||
|
||||
acpi_status __init acpi_os_initialize1(void)
|
||||
{
|
||||
kacpid_wq = alloc_workqueue("kacpid", 0, 1);
|
||||
kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 0);
|
||||
kacpid_wq = alloc_workqueue("kacpid", WQ_PERCPU, 1);
|
||||
kacpi_notify_wq = alloc_workqueue("kacpi_notify", WQ_PERCPU, 0);
|
||||
kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
|
||||
BUG_ON(!kacpid_wq);
|
||||
BUG_ON(!kacpi_notify_wq);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ static int map_x2apic_id(struct acpi_subtable_header *entry,
|
|||
if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
|
||||
return -ENODEV;
|
||||
|
||||
if (device_declaration && (apic->uid == acpi_id)) {
|
||||
if (apic->uid == acpi_id && (device_declaration || acpi_id < 255)) {
|
||||
*apic_id = apic->local_apic_id;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -732,18 +732,16 @@ static int __cpuidle acpi_idle_enter_s2idle(struct cpuidle_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
|
||||
struct cpuidle_device *dev)
|
||||
static void acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
|
||||
struct cpuidle_device *dev)
|
||||
{
|
||||
int i, count = ACPI_IDLE_STATE_START;
|
||||
struct acpi_processor_cx *cx;
|
||||
struct cpuidle_state *state;
|
||||
|
||||
if (max_cstate == 0)
|
||||
max_cstate = 1;
|
||||
|
||||
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
|
||||
state = &acpi_idle_driver.states[count];
|
||||
cx = &pr->power.states[i];
|
||||
|
||||
if (!cx->valid)
|
||||
|
|
@ -751,27 +749,13 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
|
|||
|
||||
per_cpu(acpi_cstate[count], dev->cpu) = cx;
|
||||
|
||||
if (lapic_timer_needs_broadcast(pr, cx))
|
||||
state->flags |= CPUIDLE_FLAG_TIMER_STOP;
|
||||
|
||||
if (cx->type == ACPI_STATE_C3) {
|
||||
state->flags |= CPUIDLE_FLAG_TLB_FLUSHED;
|
||||
if (pr->flags.bm_check)
|
||||
state->flags |= CPUIDLE_FLAG_RCU_IDLE;
|
||||
}
|
||||
|
||||
count++;
|
||||
if (count == CPUIDLE_STATE_MAX)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_processor_setup_cstates(struct acpi_processor *pr)
|
||||
static void acpi_processor_setup_cstates(struct acpi_processor *pr)
|
||||
{
|
||||
int i, count;
|
||||
struct acpi_processor_cx *cx;
|
||||
|
|
@ -818,17 +802,21 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr)
|
|||
if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr))
|
||||
state->enter_s2idle = acpi_idle_enter_s2idle;
|
||||
|
||||
if (lapic_timer_needs_broadcast(pr, cx))
|
||||
state->flags |= CPUIDLE_FLAG_TIMER_STOP;
|
||||
|
||||
if (cx->type == ACPI_STATE_C3) {
|
||||
state->flags |= CPUIDLE_FLAG_TLB_FLUSHED;
|
||||
if (pr->flags.bm_check)
|
||||
state->flags |= CPUIDLE_FLAG_RCU_IDLE;
|
||||
}
|
||||
|
||||
count++;
|
||||
if (count == CPUIDLE_STATE_MAX)
|
||||
break;
|
||||
}
|
||||
|
||||
drv->state_count = count;
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void acpi_processor_cstate_first_run_checks(void)
|
||||
|
|
@ -1243,7 +1231,8 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
|
|||
if (pr->flags.has_lpi)
|
||||
return acpi_processor_setup_lpi_states(pr);
|
||||
|
||||
return acpi_processor_setup_cstates(pr);
|
||||
acpi_processor_setup_cstates(pr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1263,7 +1252,8 @@ static int acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr,
|
|||
if (pr->flags.has_lpi)
|
||||
return acpi_processor_ffh_lpi_probe(pr->id);
|
||||
|
||||
return acpi_processor_setup_cpuidle_cx(pr, dev);
|
||||
acpi_processor_setup_cpuidle_cx(pr, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_processor_get_power_info(struct acpi_processor *pr)
|
||||
|
|
|
|||
|
|
@ -1280,7 +1280,7 @@ static int acpi_data_prop_read(const struct acpi_device_data *data,
|
|||
ret = acpi_copy_property_array_uint(items, (u64 *)val, nval);
|
||||
break;
|
||||
case DEV_PROP_STRING:
|
||||
nval = min_t(u32, nval, obj->package.count);
|
||||
nval = min(nval, obj->package.count);
|
||||
if (nval == 0)
|
||||
return -ENODATA;
|
||||
|
||||
|
|
@ -1329,13 +1329,14 @@ static int stop_on_next(struct acpi_device *adev, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* acpi_get_next_subnode - Return the next child node handle for a fwnode
|
||||
* @fwnode: Firmware node to find the next child node for.
|
||||
* @child: Handle to one of the device's child nodes or a null handle.
|
||||
*/
|
||||
struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child)
|
||||
static struct fwnode_handle *
|
||||
acpi_get_next_subnode(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
|
||||
|
|
@ -1472,7 +1473,7 @@ static struct fwnode_handle *acpi_graph_get_next_endpoint(
|
|||
|
||||
if (!prev) {
|
||||
do {
|
||||
port = fwnode_get_next_child_node(fwnode, port);
|
||||
port = acpi_get_next_subnode(fwnode, port);
|
||||
/*
|
||||
* The names of the port nodes begin with "port@"
|
||||
* followed by the number of the port node and they also
|
||||
|
|
@ -1490,14 +1491,17 @@ static struct fwnode_handle *acpi_graph_get_next_endpoint(
|
|||
if (!port)
|
||||
return NULL;
|
||||
|
||||
endpoint = fwnode_get_next_child_node(port, prev);
|
||||
while (!endpoint) {
|
||||
port = fwnode_get_next_child_node(fwnode, port);
|
||||
if (!port)
|
||||
do {
|
||||
endpoint = acpi_get_next_subnode(port, prev);
|
||||
if (endpoint)
|
||||
break;
|
||||
if (is_acpi_graph_node(port, "port"))
|
||||
endpoint = fwnode_get_next_child_node(port, NULL);
|
||||
}
|
||||
|
||||
prev = NULL;
|
||||
|
||||
do {
|
||||
port = acpi_get_next_subnode(fwnode, port);
|
||||
} while (port && !is_acpi_graph_node(port, "port"));
|
||||
} while (port);
|
||||
|
||||
/*
|
||||
* The names of the endpoint nodes begin with "endpoint@" followed by
|
||||
|
|
@ -1714,6 +1718,7 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
|
|||
if (fwnode_property_read_u32(fwnode, "reg", &endpoint->id))
|
||||
fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
|
||||
|
||||
fwnode_handle_put(port_fwnode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2397,7 +2397,7 @@ static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
|
|||
* initial enumeration of devices is complete, put it into the unbound
|
||||
* workqueue.
|
||||
*/
|
||||
queue_work(system_unbound_wq, &cdw->work);
|
||||
queue_work(system_dfl_wq, &cdw->work);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
|
|||
/*
|
||||
* Disable all GPE and clear their status bits before interrupts are
|
||||
* enabled. Some GPEs (like wakeup GPEs) have no handlers and this can
|
||||
* prevent them from producing spurious interrups.
|
||||
* prevent them from producing spurious interrupts.
|
||||
*
|
||||
* acpi_leave_sleep_state() will reenable specific GPEs later.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,10 +17,7 @@ static inline acpi_status acpi_set_waking_vector(u32 wakeup_address)
|
|||
|
||||
extern int acpi_s2idle_begin(void);
|
||||
extern int acpi_s2idle_prepare(void);
|
||||
extern int acpi_s2idle_prepare_late(void);
|
||||
extern void acpi_s2idle_check(void);
|
||||
extern bool acpi_s2idle_wake(void);
|
||||
extern void acpi_s2idle_restore_early(void);
|
||||
extern void acpi_s2idle_restore(void);
|
||||
extern void acpi_s2idle_end(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -1060,7 +1060,8 @@ static int __init acpi_thermal_init(void)
|
|||
}
|
||||
|
||||
acpi_thermal_pm_queue = alloc_workqueue("acpi_thermal_pm",
|
||||
WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
|
||||
WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_PERCPU,
|
||||
0);
|
||||
if (!acpi_thermal_pm_queue)
|
||||
return -ENODEV;
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ static void byt_i2c_setup(struct lpss_private_data *pdata)
|
|||
acpi_status status;
|
||||
u64 uid;
|
||||
|
||||
/* Expected to always be successfull, but better safe then sorry */
|
||||
/* Expected to always be successful, but better safe then sorry */
|
||||
if (!acpi_dev_uid_to_integer(pdata->adev, &uid) && uid) {
|
||||
/* Detect I2C bus shared with PUNIT and ignore its d3 status */
|
||||
status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
|
||||
|
|
|
|||
|
|
@ -299,34 +299,13 @@ free_acpi_buffer:
|
|||
ACPI_FREE(out_obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_get_lps0_constraint - Get the LPS0 constraint for a device.
|
||||
* @adev: Device to get the constraint for.
|
||||
*
|
||||
* The LPS0 constraint is the shallowest (minimum) power state in which the
|
||||
* device can be so as to allow the platform as a whole to achieve additional
|
||||
* energy conservation by utilizing a system-wide low-power state.
|
||||
*
|
||||
* Returns:
|
||||
* - ACPI power state value of the constraint for @adev on success.
|
||||
* - Otherwise, ACPI_STATE_UNKNOWN.
|
||||
*/
|
||||
int acpi_get_lps0_constraint(struct acpi_device *adev)
|
||||
{
|
||||
struct lpi_constraints *entry;
|
||||
|
||||
for_each_lpi_constraint(entry) {
|
||||
if (adev->handle == entry->handle)
|
||||
return entry->min_dstate;
|
||||
}
|
||||
|
||||
return ACPI_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
static void lpi_check_constraints(void)
|
||||
{
|
||||
struct lpi_constraints *entry;
|
||||
|
||||
if (IS_ERR_OR_NULL(lpi_constraints_table))
|
||||
return;
|
||||
|
||||
for_each_lpi_constraint(entry) {
|
||||
struct acpi_device *adev = acpi_fetch_acpi_dev(entry->handle);
|
||||
|
||||
|
|
@ -508,11 +487,6 @@ static int lps0_device_attach(struct acpi_device *adev,
|
|||
|
||||
lps0_device_handle = adev->handle;
|
||||
|
||||
if (acpi_s2idle_vendor_amd())
|
||||
lpi_device_get_constraints_amd();
|
||||
else
|
||||
lpi_device_get_constraints();
|
||||
|
||||
/*
|
||||
* Use suspend-to-idle by default if ACPI_FADT_LOW_POWER_S0 is set in
|
||||
* the FADT and the default suspend mode was not set from the command
|
||||
|
|
@ -539,7 +513,26 @@ static struct acpi_scan_handler lps0_handler = {
|
|||
.attach = lps0_device_attach,
|
||||
};
|
||||
|
||||
int acpi_s2idle_prepare_late(void)
|
||||
static int acpi_s2idle_begin_lps0(void)
|
||||
{
|
||||
if (pm_debug_messages_on && !lpi_constraints_table) {
|
||||
if (acpi_s2idle_vendor_amd())
|
||||
lpi_device_get_constraints_amd();
|
||||
else
|
||||
lpi_device_get_constraints();
|
||||
|
||||
/*
|
||||
* Try to retrieve the constraints only once because failures
|
||||
* to do so usually are sticky.
|
||||
*/
|
||||
if (!lpi_constraints_table)
|
||||
lpi_constraints_table = ERR_PTR(-ENODATA);
|
||||
}
|
||||
|
||||
return acpi_s2idle_begin();
|
||||
}
|
||||
|
||||
static int acpi_s2idle_prepare_late_lps0(void)
|
||||
{
|
||||
struct acpi_s2idle_dev_ops *handler;
|
||||
|
||||
|
|
@ -585,7 +578,7 @@ int acpi_s2idle_prepare_late(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void acpi_s2idle_check(void)
|
||||
static void acpi_s2idle_check_lps0(void)
|
||||
{
|
||||
struct acpi_s2idle_dev_ops *handler;
|
||||
|
||||
|
|
@ -598,7 +591,7 @@ void acpi_s2idle_check(void)
|
|||
}
|
||||
}
|
||||
|
||||
void acpi_s2idle_restore_early(void)
|
||||
static void acpi_s2idle_restore_early_lps0(void)
|
||||
{
|
||||
struct acpi_s2idle_dev_ops *handler;
|
||||
|
||||
|
|
@ -636,12 +629,12 @@ void acpi_s2idle_restore_early(void)
|
|||
}
|
||||
|
||||
static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
|
||||
.begin = acpi_s2idle_begin,
|
||||
.begin = acpi_s2idle_begin_lps0,
|
||||
.prepare = acpi_s2idle_prepare,
|
||||
.prepare_late = acpi_s2idle_prepare_late,
|
||||
.check = acpi_s2idle_check,
|
||||
.prepare_late = acpi_s2idle_prepare_late_lps0,
|
||||
.check = acpi_s2idle_check_lps0,
|
||||
.wake = acpi_s2idle_wake,
|
||||
.restore_early = acpi_s2idle_restore_early,
|
||||
.restore_early = acpi_s2idle_restore_early_lps0,
|
||||
.restore = acpi_s2idle_restore,
|
||||
.end = acpi_s2idle_end,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -150,6 +150,24 @@ static void pnp_device_shutdown(struct device *dev)
|
|||
drv->shutdown(pnp_dev);
|
||||
}
|
||||
|
||||
static int pnp_uevent(const struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct pnp_id *pos;
|
||||
const struct pnp_dev *pnp_dev = to_pnp_dev(dev);
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
pos = pnp_dev->id;
|
||||
while (pos) {
|
||||
if (add_uevent_var(env, "MODALIAS=pnp:d%s", pos->id))
|
||||
return -ENOMEM;
|
||||
pos = pos->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pnp_bus_match(struct device *dev, const struct device_driver *drv)
|
||||
{
|
||||
struct pnp_dev *pnp_dev = to_pnp_dev(dev);
|
||||
|
|
@ -259,6 +277,7 @@ static const struct dev_pm_ops pnp_bus_dev_pm_ops = {
|
|||
const struct bus_type pnp_bus_type = {
|
||||
.name = "pnp",
|
||||
.match = pnp_bus_match,
|
||||
.uevent = pnp_uevent,
|
||||
.probe = pnp_device_probe,
|
||||
.remove = pnp_device_remove,
|
||||
.shutdown = pnp_device_shutdown,
|
||||
|
|
|
|||
|
|
@ -1157,12 +1157,7 @@ struct acpi_s2idle_dev_ops {
|
|||
#if defined(CONFIG_SUSPEND) && defined(CONFIG_X86)
|
||||
int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg);
|
||||
void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg);
|
||||
int acpi_get_lps0_constraint(struct acpi_device *adev);
|
||||
#else /* CONFIG_SUSPEND && CONFIG_X86 */
|
||||
static inline int acpi_get_lps0_constraint(struct device *dev)
|
||||
{
|
||||
return ACPI_STATE_UNKNOWN;
|
||||
}
|
||||
static inline int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg)
|
||||
{
|
||||
return -ENODEV;
|
||||
|
|
@ -1360,9 +1355,6 @@ acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid,
|
|||
int acpi_node_prop_get(const struct fwnode_handle *fwnode, const char *propname,
|
||||
void **valptr);
|
||||
|
||||
struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child);
|
||||
|
||||
struct acpi_probe_entry;
|
||||
typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *,
|
||||
struct acpi_probe_entry *);
|
||||
|
|
@ -1461,13 +1453,6 @@ static inline int acpi_node_prop_get(const struct fwnode_handle *fwnode,
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *
|
||||
acpi_get_next_subnode(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *
|
||||
acpi_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *prev)
|
||||
|
|
|
|||
|
|
@ -39,9 +39,7 @@ impl DeviceId {
|
|||
pub const fn new(id: &'static CStr) -> Self {
|
||||
let src = id.to_bytes_with_nul();
|
||||
build_assert!(src.len() <= Self::ACPI_ID_LEN, "ID exceeds 16 bytes");
|
||||
// Replace with `bindings::acpi_device_id::default()` once stabilized for `const`.
|
||||
// SAFETY: FFI type is valid to be zero-initialized.
|
||||
let mut acpi: bindings::acpi_device_id = unsafe { core::mem::zeroed() };
|
||||
let mut acpi: bindings::acpi_device_id = pin_init::zeroed();
|
||||
let mut i = 0;
|
||||
while i < src.len() {
|
||||
acpi.id[i] = src[i];
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ int main(int argc, char *argv[])
|
|||
fd_update_log = open("/dev/acpi_pfr_telemetry0", O_RDWR);
|
||||
if (fd_update_log < 0) {
|
||||
printf("PFRT device not supported - Quit...\n");
|
||||
close(fd_update);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +266,8 @@ int main(int argc, char *argv[])
|
|||
printf("chunk2_size:%d\n", data_info.chunk2_size);
|
||||
printf("rollover_cnt:%d\n", data_info.rollover_cnt);
|
||||
printf("reset_cnt:%d\n", data_info.reset_cnt);
|
||||
|
||||
close(fd_update);
|
||||
close(fd_update_log);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -358,6 +360,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (ret == -1) {
|
||||
perror("Failed to load capsule file");
|
||||
munmap(addr_map_capsule, st.st_size);
|
||||
close(fd_capsule);
|
||||
close(fd_update);
|
||||
close(fd_update_log);
|
||||
|
|
@ -420,7 +423,7 @@ int main(int argc, char *argv[])
|
|||
if (p_mmap == MAP_FAILED) {
|
||||
perror("mmap error.");
|
||||
close(fd_update_log);
|
||||
|
||||
free(log_buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue