Re: Re: managing a fan speed via memory address

From: Dmitry N. Medvedev <dmitry.medvedev_at_gmail.com>
Date: Thu, 04 May 2023 13:45:22 UTC
hi Georg,

it's become even more confusing -- none of the IDs from #1 exist in
acpidump output :(

researching further

On Wed, May 3, 2023 at 8:02 PM Georg Lindenberg <georg.lindenberg@web.de>
wrote:

>
> Hello,
>
> ACPI can control fans, but it is up to the hardware manufacturer (OEM) to
> implement it.
>
> _______________________________
> Step 1. Check for ACPI fan control
>
> The OEM needs to add a device with id "PNP0C0B" to the acpi namespace.
> In FreeBSD, you can test this with the command: acpidump -d -t | grep
> PNP0C0B
>
> On Windows, you can download acpi tools at
> https://acpica.org/downloads/binary-tools
> Then use the command: acpidump.exe | findstr PNP0C0B
>
> Some fans use IDs which are not documented in the ACPI specification:
>     "PNP0C0B",         /* Generic Fan */ \
>     "INT3404",        /* Fan */ \
>     "INTC1044",        /* Fan for Tiger Lake generation */
>     "INTC1048",     /* Fan for Alder Lake generation */
>     "INTC1063",    /* Fan for Meteor Lake generation */
>     "INTC10A2",    /* Fan for Raptor Lake generation */
>
> You might want to search for these strings as well.
>
> __________________________
> Step 2. Check for version of ACPI
>
> Fan version is either 1.0 or 4.0.
>
> a) Acpi version 1.0
>
> If you suceed with step 1., then you can communicate with the fan. You can
> turn it on and off
> by putting it in power state D0 or D3.
> In C, you would probably use acpi_set_powerstate(dev, ACPI_STATE_D3),
> or maybe use acpi power methods, like _ON, _OFF, _PR3, _PR0 (haven't
> tested it).
>
> Or maybe an alternative: There is a suggestion on FreeBSD acpi wiki:
> device_power -- Add a "power" argument to devctl(8) that allows a device
> to be set into various low power or off states.
> Noone has implemented that yet ("not done"). :)
>
> b) ACPI version 4.0
>
> To check, whether your fan supports fan levels, you can do this:
>
> OEM _must_ provide four predefined acpi methods. They are described in
> detail in the acpi
> specification. They are called: _FIF, _FPS, _FSL, _FST
> So just use:
> acpidump -d -t | grep _FPS
> and so on. If all four are present, you can use fan levels! :-)
>
> In your source code, it could look like this:
>
>     ACPI_HANDLE    handle;
>     ACPI_HANDLE tmp;
>
>     /* fans are either acpi 1.0 or 4.0 compatible, so check now. */
>      if (ACPI_SUCCESS(acpi_get_handle(handle, "_FIF", &tmp)) &&
>     ACPI_SUCCESS(acpi_get_handle(handle, "_FPS", &tmp)) &&
>     ACPI_SUCCESS(acpi_get_handle(handle, "_FSL", &tmp)) &&
>     ACPI_SUCCESS(acpi_get_handle(handle, "_FST", &tmp)))
>         acpi_fan_initiate_acpi4(dev);
>
>     else    /* nothing to do in acpi version 1, really */
>         acpi_fan_softc.version = 1;
>
> 3. How to set fan levels
>
> As a driver author, you'd need to decide how you'd want to implement the
> fan level. It can be done
> via /dev/acpi (and also add code to acpiconf (8)). Or it can be done via
> systctls.
>
> So in your code, you could add a proc sysctl. There are multiple ways to
> implement sysctls,
> one way could be this:
>
>     sysctl_ctx_init(&clist);        /* sysctl context */
>
>     struct sysctl_oid *fan_oid = device_get_sysctl_tree(dev);
>     SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(fan_oid), OID_AUTO,
>     "Fan level", CTLTYPE_INT | CTLFLAG_RW, 0, 0,
>     acpi_fan_level_sysctl, "I" ,"Fan level");
>
> Or whatever code you like.
>
> Then you need a sysctl handler:
>
> static int
> acpi_fan_level_sysctl(SYSCTL_HANDLER_ARGS) {
>
> ...
> }
>
> In the handler function you could "handle" the fan level, and probably call
> acpi_evaluate_object() on the _FIF, _FPS, _FSL, and _FST methods.
>
> Unfortunately, my laptops don't support fans at all. So I can't really
> write a fan driver.
> I think it is a good beginners task.
>
> Basically, if your fan has three or four pins, it might support fan
> levels. The first two pins are
> used for electricity. The third pin is used to upscale or downscale the
> power (voltage?),
> thus increasing or decreasing the fan speed. There is no magic to this.
>
> 4. Sceleton acpi driver
>
> If you need a sceleton acpi driver, that shouldn't be a problem.
> FreeBSD puts all acpi drivers (modules) into the acpi subsystem
> (sys/dev/acpica), instead
> of giving them a separate makefile in sys/modules.
>
> This was my first attempt, without ever testing anything (bugs to be
> expected): :-)
>
> #include "opt_acpi.h"
> #include <sys/param.h>
> #include <sys/kernel.h>
> #include <sys/module.h>
>
> /* for testing, aka printf */
> #include <sys/types.h>
> #include <sys/systm.h>
>
> #include <contrib/dev/acpica/include/acpi.h>
> #include <dev/acpica/acpivar.h>
> #include <dev/acpica/acpiio.h>
>
> /* Hooks for the ACPI CA debugging infrastructure */
> #define    _COMPONENT    ACPI_FAN
> ACPI_MODULE_NAME("FAN")
>
> /* driver software context */
> struct acpi_fan_softc {
>     device_t    dev;
>     int            version;    /* either ACPI 1.0 or 4.0 */
> };
>
> static device_method_t acpi_fan_methods[] = {
>     /* Device interface */
>     DEVMETHOD(device_probe,        acpi_fan_probe),
>     DEVMETHOD(device_attach,    acpi_fan_attach),
>     DEVMETHOD(device_detach,    acpi_fan_detach),
>     DEVMETHOD_END
> };
>
> static int
> acpi_fan_probe(device_t dev)
> {
>     static char *fan_ids[] = { \
>     "PNP0C0B",         /* Generic Fan */ \
>     "INT3404",        /* Fan */ \
>     "INTC1044",        /* Fan for Tiger Lake generation */ \
>     "INTC1048",     /* Fan for Alder Lake generation */ \
>     "INTC1063",     /* Fan for Meteor Lake generation */ \
>     "INTC10A2",     /* Fan for Raptor Lake generation */ \
>     NULL };
>     int rv;
>
>     if (acpi_disabled("fan"))
>     return (ENXIO);
>     rv = ACPI_ID_PROBE(device_get_parent(dev), dev, fan_ids, NULL);
>     if (rv <= 0)
>     device_set_desc(dev, "ACPI FAN");
>     return (rv);
> }
>
> static int
> acpi_fan_attach(device_t dev)
> {
>     int    error;
>     ACPI_HANDLE    handle;
>     ACPI_HANDLE tmp;
>     struct acpi_fan_softc *sc;
>
>     sc = device_get_softc(dev);
>     handle = acpi_get_handle(dev);
>
>     /* fans are either acpi 1.0 or 4.0 compatible, so check now. */
>     if (ACPI_SUCCESS(acpi_get_handle(handle, "_FIF", &tmp)) &&
>     ACPI_SUCCESS(acpi_get_handle(handle, "_FPS", &tmp)) &&
>     ACPI_SUCCESS(acpi_get_handle(handle, "_FSL", &tmp)) &&
>     ACPI_SUCCESS(acpi_get_handle(handle, "_FST", &tmp)))
>         acpi_fan_softc.version = 4;
>
>     else    /* nothing to do in acpi version 1, really */
>         acpi_fan_softc.version = 1;
>
>   return 0;
> }
>
> static int
> acpi_fan_detach(device_t dev) {
>     sysctl_ctx_free(&clist);
>     return 0;
> }
>
>
> static driver_t acpi_fan_driver = {
>     "fan",
>     acpi_fan_methods,
>     sizeof(struct acpi_fan_softc),
> };
> DRIVER_MODULE(acpi_fan, acpi, acpi_fan_driver, 0, 0);
> MODULE_DEPEND(acpi_fan, acpi, 1, 1, 1);
>
> _____________________
> 5. How linux does it
>
> You can check linux fan driver on github:
> https://github.com/torvalds/linux/tree/master/drivers/acpi
>
> They separate the driver into three files.
> fan.h
> fan_attr.c
> fan_core.c
>
> It's ok to learn from linux. :-)
>
>
> Sorry for long message.
> Georg.
> *Gesendet:* Mittwoch, 03. Mai 2023 um 02:26 Uhr
> *Von:* "Dmitry N. Medvedev" <dmitry.medvedev@gmail.com>
> *An:* "Adrian Chadd" <adrian@freebsd.org>
> *Cc:* freebsd-acpi@freebsd.org
> *Betreff:* Re: managing a fan speed via memory address
> good morning Adrian,
>
> 1. I am just learning :) Not 100% sure ACPI has anything to do with fan
> control ( still it looks that it actually does )
> -- found the Advanced Configuration and Power Interface Specification PDF.
> Will spend some time grasping the ideas
> 2. to quickly write any driver I will have to first find out how to do it
> :) any guidance ( preferable in textual form will be greatly appreciated )
> will learn it :)
> 3. there isn't a single thermal sensor, but the SAS disks report their
> temperatures
> ( via dmidecode if I am not mistaken, or some other program -- I will be
> more sure tomorrow morning ).
> so, theoretically I could be able to read their temperature and decide if
> I would like to send more power to the fan.
>
> On Wed, May 3, 2023 at 2:14 AM Adrian Chadd <adrian@freebsd.org> wrote:
>
>> Is it not an ACPI driver? If not, you could write a quick fan driver!
>>
>> Is there a thermal sensor(s) you could read to see how warm they get?
>>
>>
>>
>> -adrian
>>
>>
>> On Tue, 2 May 2023 at 17:06, Dmitry N. Medvedev <
>> dmitry.medvedev@gmail.com> wrote:
>>
>>> good morning,
>>>
>>> Recently I have learned about the dmidecode program and found the
>>> address of the FRNTFAN port in my HP Z420 machine: 0x0037.
>>> Since I am a complete newbie, I would like to learn if there is a way to
>>> read and change the value at this address.
>>> I need a bit of guidance.
>>>
>>> *The context*: I have added 8 SAS disks to the machine, put noctua fan
>>> in front of them and connected the fan to the FRNTFAN port on the
>>> motherboard.
>>> It looks like the fan works, but I am sure the disks would benefit if
>>> the fan produced more pressure. Which I fantasize I could do via changing
>>> the value at the said address.
>>> Not sure, of course.
>>>
>>> best regards,
>>> Dmitry N. Medvedev
>>>
>>