Merge tag 'acpi-6.18-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI fixes from Rafael Wysocki:
 "These fix three ACPI driver issues and add version checks to two ACPI
  table parsers:

   - Call input_free_device() on failing input device registration as
     necessary (and mentioned in the input subsystem documentation) in
     the ACPI button driver (Kaushlendra Kumar)

   - Fix use-after-free in acpi_video_switch_brightness() by canceling a
     delayed work during tear-down (Yuhao Jiang)

   - Use platform device for devres-related actions in the ACPI fan
     driver to allow device-managed resources to be cleaned up properly
     (Armin Wolf)

   - Add version checks to the MRRM and SPCR table parsers (Tony Luck
     and Punit Agrawal)"

* tag 'acpi-6.18-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI: SPCR: Check for table version when using precise baudrate
  ACPI: MRRM: Check revision of MRRM table
  ACPI: fan: Use platform device for devres-related actions
  ACPI: fan: Use ACPI handle when retrieving _FST
  ACPI: video: Fix use-after-free in acpi_video_switch_brightness()
  ACPI: button: Call input_free_device() on failing input device registration
This commit is contained in:
Linus Torvalds
2025-10-30 19:05:46 -07:00
8 changed files with 43 additions and 26 deletions

View File

@@ -63,6 +63,9 @@ static __init int acpi_parse_mrrm(struct acpi_table_header *table)
if (!mrrm)
return -ENODEV;
if (mrrm->header.revision != 1)
return -EINVAL;
if (mrrm->flags & ACPI_MRRM_FLAGS_REGION_ASSIGNMENT_OS)
return -EOPNOTSUPP;

View File

@@ -1959,8 +1959,10 @@ static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video)
struct acpi_video_device *dev;
mutex_lock(&video->device_list_lock);
list_for_each_entry(dev, &video->video_device_list, entry)
list_for_each_entry(dev, &video->video_device_list, entry) {
acpi_video_dev_remove_notify_handler(dev);
cancel_delayed_work_sync(&dev->switch_brightness_work);
}
mutex_unlock(&video->device_list_lock);
acpi_video_bus_stop_devices(video);

View File

@@ -619,8 +619,10 @@ static int acpi_button_add(struct acpi_device *device)
input_set_drvdata(input, device);
error = input_register_device(input);
if (error)
if (error) {
input_free_device(input);
goto err_remove_fs;
}
switch (device->device_type) {
case ACPI_BUS_TYPE_POWER_BUTTON:

View File

@@ -49,6 +49,7 @@ struct acpi_fan_fst {
};
struct acpi_fan {
acpi_handle handle;
bool acpi4;
bool has_fst;
struct acpi_fan_fif fif;
@@ -59,14 +60,14 @@ struct acpi_fan {
struct device_attribute fine_grain_control;
};
int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst);
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 acpi_device *device);
int devm_acpi_fan_create_hwmon(struct device *dev);
#else
static inline int devm_acpi_fan_create_hwmon(struct acpi_device *device) { return 0; };
static inline int devm_acpi_fan_create_hwmon(struct device *dev) { return 0; };
#endif
#endif

View File

@@ -55,7 +55,7 @@ static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr,
struct acpi_fan_fst fst;
int status;
status = acpi_fan_get_fst(acpi_dev, &fst);
status = acpi_fan_get_fst(acpi_dev->handle, &fst);
if (status)
return status;

View File

@@ -44,25 +44,30 @@ static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
return 0;
}
int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst)
int acpi_fan_get_fst(acpi_handle handle, struct acpi_fan_fst *fst)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
int ret = 0;
status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
dev_err(&device->dev, "Get fan state failed\n");
return -ENODEV;
}
status = acpi_evaluate_object(handle, "_FST", NULL, &buffer);
if (ACPI_FAILURE(status))
return -EIO;
obj = buffer.pointer;
if (!obj || obj->type != ACPI_TYPE_PACKAGE ||
obj->package.count != 3 ||
obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
dev_err(&device->dev, "Invalid _FST data\n");
ret = -EINVAL;
if (!obj)
return -ENODATA;
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) {
ret = -EPROTO;
goto err;
}
if (obj->package.elements[0].type != ACPI_TYPE_INTEGER ||
obj->package.elements[1].type != ACPI_TYPE_INTEGER ||
obj->package.elements[2].type != ACPI_TYPE_INTEGER) {
ret = -EPROTO;
goto err;
}
@@ -81,7 +86,7 @@ static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
struct acpi_fan_fst fst;
int status, i;
status = acpi_fan_get_fst(device, &fst);
status = acpi_fan_get_fst(device->handle, &fst);
if (status)
return status;
@@ -311,11 +316,16 @@ static int acpi_fan_probe(struct platform_device *pdev)
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
char *name;
if (!device)
return -ENODEV;
fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
if (!fan) {
dev_err(&device->dev, "No memory for fan\n");
return -ENOMEM;
}
fan->handle = device->handle;
device->driver_data = fan;
platform_set_drvdata(pdev, fan);
@@ -337,7 +347,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
}
if (fan->has_fst) {
result = devm_acpi_fan_create_hwmon(device);
result = devm_acpi_fan_create_hwmon(&pdev->dev);
if (result)
return result;

View File

@@ -93,13 +93,12 @@ static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_
static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct acpi_device *adev = to_acpi_device(dev->parent);
struct acpi_fan *fan = dev_get_drvdata(dev);
struct acpi_fan_fps *fps;
struct acpi_fan_fst fst;
int ret;
ret = acpi_fan_get_fst(adev, &fst);
ret = acpi_fan_get_fst(fan->handle, &fst);
if (ret < 0)
return ret;
@@ -167,12 +166,12 @@ static const struct hwmon_chip_info acpi_fan_hwmon_chip_info = {
.info = acpi_fan_hwmon_info,
};
int devm_acpi_fan_create_hwmon(struct acpi_device *device)
int devm_acpi_fan_create_hwmon(struct device *dev)
{
struct acpi_fan *fan = acpi_driver_data(device);
struct acpi_fan *fan = dev_get_drvdata(dev);
struct device *hdev;
hdev = devm_hwmon_device_register_with_info(&device->dev, "acpi_fan", fan,
&acpi_fan_hwmon_chip_info, NULL);
hdev = devm_hwmon_device_register_with_info(dev, "acpi_fan", fan, &acpi_fan_hwmon_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hdev);
}

View File

@@ -155,7 +155,7 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
* Baud Rate field. If this field is zero or not present, Configured
* Baud Rate is used.
*/
if (table->precise_baudrate)
if (table->header.revision >= 4 && table->precise_baudrate)
baud_rate = table->precise_baudrate;
else switch (table->baud_rate) {
case 0: