Skip to content

Commit 2e00f7a

Browse files
Wer-Wolfrafaeljw
authored andcommitted
ACPI: fan: Workaround for 64-bit firmware bug
Some firmware implementations use the "Ones" ASL opcode to produce an integer with all bits set in order to indicate missing speed or power readings. This however only works when using 32-bit integers, as the ACPI spec requires a 32-bit integer (0xFFFFFFFF) to be returned for missing speed/power readings. With 64-bit integers the "Ones" opcode produces a 64-bit integer with all bits set, violating the ACPI spec regarding the placeholder value for missing readings. Work around such buggy firmware implementation by also checking for 64-bit integers with all bits set when reading _FST. Signed-off-by: Armin Wolf <W_Armin@gmx.de> [ rjw: Typo fix in the changelog ] Link: https://patch.msgid.link/20251007234149.2769-3-W_Armin@gmx.de Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent d91a1d1 commit 2e00f7a

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

drivers/acpi/fan.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define _ACPI_FAN_H_
1212

1313
#include <linux/kconfig.h>
14+
#include <linux/limits.h>
1415

1516
#define ACPI_FAN_DEVICE_IDS \
1617
{"INT3404", }, /* Fan */ \
@@ -60,6 +61,38 @@ struct acpi_fan {
6061
struct device_attribute fine_grain_control;
6162
};
6263

64+
/**
65+
* acpi_fan_speed_valid - Check if fan speed value is valid
66+
* @speeed: Speed value returned by the ACPI firmware
67+
*
68+
* Check if the fan speed value returned by the ACPI firmware is valid. This function is
69+
* necessary as ACPI firmware implementations can return 0xFFFFFFFF to signal that the
70+
* ACPI fan does not support speed reporting. Additionally, some buggy ACPI firmware
71+
* implementations return a value larger than the 32-bit integer value defined by
72+
* the ACPI specification when using placeholder values. Such invalid values are also
73+
* detected by this function.
74+
*
75+
* Returns: True if the fan speed value is valid, false otherwise.
76+
*/
77+
static inline bool acpi_fan_speed_valid(u64 speed)
78+
{
79+
return speed < U32_MAX;
80+
}
81+
82+
/**
83+
* acpi_fan_power_valid - Check if fan power value is valid
84+
* @power: Power value returned by the ACPI firmware
85+
*
86+
* Check if the fan power value returned by the ACPI firmware is valid.
87+
* See acpi_fan_speed_valid() for details.
88+
*
89+
* Returns: True if the fan power value is valid, false otherwise.
90+
*/
91+
static inline bool acpi_fan_power_valid(u64 power)
92+
{
93+
return power < U32_MAX;
94+
}
95+
6396
int acpi_fan_get_fst(acpi_handle handle, struct acpi_fan_fst *fst);
6497
int acpi_fan_create_attributes(struct acpi_device *device);
6598
void acpi_fan_delete_attributes(struct acpi_device *device);

drivers/acpi/fan_hwmon.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515

1616
#include "fan.h"
1717

18-
/* Returned when the ACPI fan does not support speed reporting */
19-
#define FAN_SPEED_UNAVAILABLE U32_MAX
20-
#define FAN_POWER_UNAVAILABLE U32_MAX
21-
2218
static struct acpi_fan_fps *acpi_fan_get_current_fps(struct acpi_fan *fan, u64 control)
2319
{
2420
unsigned int i;
@@ -77,7 +73,7 @@ static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_
7773
* when the associated attribute should not be created.
7874
*/
7975
for (i = 0; i < fan->fps_count; i++) {
80-
if (fan->fps[i].power != FAN_POWER_UNAVAILABLE)
76+
if (acpi_fan_power_valid(fan->fps[i].power))
8177
return 0444;
8278
}
8379

@@ -106,7 +102,7 @@ static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
106102
case hwmon_fan:
107103
switch (attr) {
108104
case hwmon_fan_input:
109-
if (fst.speed == FAN_SPEED_UNAVAILABLE)
105+
if (!acpi_fan_speed_valid(fst.speed))
110106
return -ENODEV;
111107

112108
if (fst.speed > LONG_MAX)
@@ -134,7 +130,7 @@ static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
134130
if (!fps)
135131
return -EIO;
136132

137-
if (fps->power == FAN_POWER_UNAVAILABLE)
133+
if (!acpi_fan_power_valid(fps->power))
138134
return -ENODEV;
139135

140136
if (fps->power > LONG_MAX / MICROWATT_PER_MILLIWATT)

0 commit comments

Comments
 (0)