Re: Re: managing a fan speed via memory address
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 >>> >>