Re: [PATCH] ACPI: fan: Add fan speed reporting for fans with only _FST

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Den tors 23 jan. 2025 kl 01:50 skrev Armin Wolf <W_Armin@xxxxxx>:
>
> Am 14.01.25 um 02:21 schrieb Joshua Grisham:
>
> > Add support for ACPI fans with _FST to report their speed even if they do
> > not support fan control.
> >
> > As suggested by Armin Wolf [1] and per the Windows Thermal Management
> > Design Guide [2], Samsung Galaxy Book series devices (and possibly many
> > more devices where the Windows guide was strictly followed) only implement
> > the _FST method and do not support ACPI-based fan control.
> >
> > Currently, these fans are not supported by the kernel driver but this patch
> > will make some very small adjustments to allow them to be supported.
> >
> > This patch is tested and working for me on a Samsung Galaxy Book2 Pro whose
> > DSDT (and several other Samsung Galaxy Book series notebooks which
> > currently have the same issue) can be found at [3].
> >
> > [1]: https://lore.kernel.org/platform-driver-x86/53c5075b-1967-45d0-937f-463912dd966d@xxxxxx
> > [2]: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/design-guide
> > [3]: https://github.com/joshuagrisham/samsung-galaxybook-extras/tree/8e3087a06b8bdcdfdd081367af4b744a56cc4ee9/dsdt
> >
> > Signed-off-by: Joshua Grisham <josh@xxxxxxxxxxxxxxxxx>
> > ---
> >   drivers/acpi/fan.h       |  1 +
> >   drivers/acpi/fan_attr.c  | 37 ++++++++++++++++++++++---------------
> >   drivers/acpi/fan_core.c  | 24 ++++++++++++++++--------
> >   drivers/acpi/fan_hwmon.c |  6 ++++++
> >   4 files changed, 45 insertions(+), 23 deletions(-)
> >
> > diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h
> > index 488b51e2c..d0aad88a7 100644
> > --- a/drivers/acpi/fan.h
> > +++ b/drivers/acpi/fan.h
> > @@ -49,6 +49,7 @@ struct acpi_fan_fst {
> >
> >   struct acpi_fan {
> >       bool acpi4;
> > +     bool acpi4_only_fst;
> >       struct acpi_fan_fif fif;
> >       struct acpi_fan_fps *fps;
> >       int fps_count;
> > diff --git a/drivers/acpi/fan_attr.c b/drivers/acpi/fan_attr.c
> > index f4f6e2381..d83f88429 100644
> > --- a/drivers/acpi/fan_attr.c
> > +++ b/drivers/acpi/fan_attr.c
> > @@ -75,15 +75,6 @@ int acpi_fan_create_attributes(struct acpi_device *device)
> >       struct acpi_fan *fan = acpi_driver_data(device);
> >       int i, status;
> >
> > -     sysfs_attr_init(&fan->fine_grain_control.attr);
> > -     fan->fine_grain_control.show = show_fine_grain_control;
> > -     fan->fine_grain_control.store = NULL;
> > -     fan->fine_grain_control.attr.name = "fine_grain_control";
> > -     fan->fine_grain_control.attr.mode = 0444;
> > -     status = sysfs_create_file(&device->dev.kobj, &fan->fine_grain_control.attr);
> > -     if (status)
> > -             return status;
> > -
> >       /* _FST is present if we are here */
> >       sysfs_attr_init(&fan->fst_speed.attr);
> >       fan->fst_speed.show = show_fan_speed;
> > @@ -92,7 +83,19 @@ int acpi_fan_create_attributes(struct acpi_device *device)
> >       fan->fst_speed.attr.mode = 0444;
> >       status = sysfs_create_file(&device->dev.kobj, &fan->fst_speed.attr);
> >       if (status)
> > -             goto rem_fine_grain_attr;
> > +             return status;
> > +
> > +     if (fan->acpi4_only_fst)
> > +             return 0;
> > +
> > +     sysfs_attr_init(&fan->fine_grain_control.attr);
> > +     fan->fine_grain_control.show = show_fine_grain_control;
> > +     fan->fine_grain_control.store = NULL;
> > +     fan->fine_grain_control.attr.name = "fine_grain_control";
> > +     fan->fine_grain_control.attr.mode = 0444;
> > +     status = sysfs_create_file(&device->dev.kobj, &fan->fine_grain_control.attr);
> > +     if (status)
> > +             goto rem_fst_attr;
> >
> >       for (i = 0; i < fan->fps_count; ++i) {
> >               struct acpi_fan_fps *fps = &fan->fps[i];
> > @@ -109,18 +112,18 @@ int acpi_fan_create_attributes(struct acpi_device *device)
> >
> >                       for (j = 0; j < i; ++j)
> >                               sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);
> > -                     goto rem_fst_attr;
> > +                     goto rem_fine_grain_attr;
> >               }
> >       }
> >
> >       return 0;
> >
> > -rem_fst_attr:
> > -     sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
> > -
> >   rem_fine_grain_attr:
> >       sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr);
> >
> > +rem_fst_attr:
> > +     sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
> > +
> >       return status;
> >   }
> >
> > @@ -129,9 +132,13 @@ void acpi_fan_delete_attributes(struct acpi_device *device)
> >       struct acpi_fan *fan = acpi_driver_data(device);
> >       int i;
> >
> > +     sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
> > +
> > +     if (fan->acpi4_only_fst)
> > +             return;
> > +
> >       for (i = 0; i < fan->fps_count; ++i)
> >               sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
> >
> > -     sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
> >       sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr);
> >   }
> > diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c
> > index 10016f52f..b51b1481c 100644
> > --- a/drivers/acpi/fan_core.c
> > +++ b/drivers/acpi/fan_core.c
> > @@ -211,6 +211,11 @@ static bool acpi_fan_is_acpi4(struct acpi_device *device)
> >              acpi_has_method(device->handle, "_FST");
> >   }
> >
> > +static bool acpi_fan_has_fst(struct acpi_device *device)
> > +{
> > +     return acpi_has_method(device->handle, "_FST");
> > +}
> > +
> >   static int acpi_fan_get_fif(struct acpi_device *device)
> >   {
> >       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
> > @@ -327,7 +332,12 @@ static int acpi_fan_probe(struct platform_device *pdev)
> >       device->driver_data = fan;
> >       platform_set_drvdata(pdev, fan);
> >
> > -     if (acpi_fan_is_acpi4(device)) {
> > +     if (acpi_fan_is_acpi4(device))
> > +             fan->acpi4 = true;
> > +     else if (acpi_fan_has_fst(device))
> > +             fan->acpi4_only_fst = true;
> > +
> > +     if (fan->acpi4) {
> >               result = acpi_fan_get_fif(device);
> >               if (result)
> >                       return result;
> > @@ -335,7 +345,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
> >               result = acpi_fan_get_fps(device);
> >               if (result)
> >                       return result;
> > -
> > +     } else if (fan->acpi4 || fan->acpi4_only_fst) {
>
> Hi,
>
> this will not register any attributes or the hwmon interface if "fan->acpi4" is true.
>
> I think the "else" is misplaced here.
>
> >               result = devm_acpi_fan_create_hwmon(device);
> >               if (result)
> >                       return result;
> > @@ -343,8 +353,6 @@ static int acpi_fan_probe(struct platform_device *pdev)
> >               result = acpi_fan_create_attributes(device);
> >               if (result)
> >                       return result;
> > -
> > -             fan->acpi4 = true;
> >       } else {
> >               result = acpi_device_update_power(device, NULL);
> >               if (result) {
> > @@ -391,7 +399,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
> >   err_unregister:
> >       thermal_cooling_device_unregister(cdev);
> >   err_end:
> > -     if (fan->acpi4)
> > +     if (fan->acpi4 || fan->acpi4_only_fst)
> >               acpi_fan_delete_attributes(device);
> >
> >       return result;
> > @@ -401,7 +409,7 @@ static void acpi_fan_remove(struct platform_device *pdev)
> >   {
> >       struct acpi_fan *fan = platform_get_drvdata(pdev);
> >
> > -     if (fan->acpi4) {
> > +     if (fan->acpi4 || fan->acpi4_only_fst) {
> >               struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
> >
> >               acpi_fan_delete_attributes(device);
> > @@ -415,7 +423,7 @@ static void acpi_fan_remove(struct platform_device *pdev)
> >   static int acpi_fan_suspend(struct device *dev)
> >   {
> >       struct acpi_fan *fan = dev_get_drvdata(dev);
> > -     if (fan->acpi4)
> > +     if (fan->acpi4 || fan->acpi4_only_fst)
> >               return 0;
> >
> >       acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0);
> > @@ -428,7 +436,7 @@ static int acpi_fan_resume(struct device *dev)
> >       int result;
> >       struct acpi_fan *fan = dev_get_drvdata(dev);
> >
> > -     if (fan->acpi4)
> > +     if (fan->acpi4 || fan->acpi4_only_fst)
> >               return 0;
>
> The Windows design guide says:
>
>         "A fan that implements the _FST object is not required to be in a thermal
>         zone's _ALx device list, but it can, as an option, be in this list.
>         This option enables a hybrid solution in which a fan is typically
>         controlled by a third-party driver, but can be controlled by the OS
>         thermal zone if the third-party driver is not installed. If a fan is in
>         an _ALx device list and is engaged by the thermal zone (placed in D0),
>         the _FST object is required to indicate a nonzero Control value."
>
> Because this i think the suspend/resume path should still change the power state of the fan device.
>
> >
> >       result = acpi_device_update_power(ACPI_COMPANION(dev), NULL);
> > diff --git a/drivers/acpi/fan_hwmon.c b/drivers/acpi/fan_hwmon.c
> > index bd0d31a39..87bee018c 100644
> > --- a/drivers/acpi/fan_hwmon.c
> > +++ b/drivers/acpi/fan_hwmon.c
> > @@ -43,6 +43,12 @@ static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_
> >               case hwmon_fan_input:
> >                       return 0444;
> >               case hwmon_fan_target:
> > +                     /*
> > +                      * Fans with only _FST do not support fan control.
> > +                      */
> > +                     if (fan->acpi4_only_fst)
> > +                             return 0;
>
> The same needs to be done for hwmon_power_input, since currently the code assumes that the _FIF
> ACPI control method is always present.
>
> Other than that the patch looks promising.
>
> Thanks,
> Armin Wolf
>

Hi Armin! I looked at this and you are 100% right on all counts, thank
you for checking into this! For the really silly stuff, I can only
blame that it was apparently very late when I sent this patch in :) I
will update these now, do a quick test to make sure things are looking
ok still, and send a v2 of the patch.

Thank you again!

Best regards,
Joshua




[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]
  Powered by Linux