Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 06 Jul 2005 17:59:19 -0700
From:      Nate Lawson <nate@root.org>
To:        Hajimu UMEMOTO <ume@FreeBSD.org>
Cc:        acpi@FreeBSD.org, takawata@FreeBSD.org
Subject:   passive cooling and cpufreq
Message-ID:  <42CC7E67.50401@root.org>
In-Reply-To: <yger7ebsv9r.wl%ume@mahoroba.org>
References:  <42CB0369.1000701@root.org> <yger7ebsv9r.wl%ume@mahoroba.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Hajimu UMEMOTO wrote:
>> Nate Lawson <nate@root.org> said:
> nate> ume@ showed a patch for passive cooling in usermode via powerd(8).  I 
> nate> recommended he port it to acpi_thermal kernel mode.  The cpufreq kernel 
> nate> interface (see cpufreq_if.m and cpufreq(4)) shows how to control CPU 
> nate> frequency from other kernel drivers.
> 
> I made in-kernel version of passive cooling already, and it seems
> working fine on my laptop:
> 
> 	http://www.imasy.or.jp/~ume/FreeBSD/passive-cooling-20050703.diff
> 
> However, there are some issue.
> I added some funtions into kern_cpu.c and call them from
> acpi_thermal.c directly.  Perhaps, we should call cpufreq stuff via
> acpi_perf to see _PSL for mapping between thermal zone and CPU.  But,
> acpi_perf doesn't appered on my CF-R4.  It seems that
> acpi_perf_attach() returns 0, but sc->info_only is on.  Is it correct
> behavior?
> Further, there is conflict with userland, in short powerd(8).  So, I
> needed to modify cpufreq_curr_sysctl() to fake frequency.  Instead, I
> implemented to be able to obtain actuall frequency via
> dev.cpu.0.realdreq.

I have moved this email to acpi@ for general discussion.

There is a much simpler way to access cpufreq(4) from the kernel that 
shouldn't require modifications.  It exports newbus methods for 
controling the frequency.  This kind of code should work:


#include <cpufreq.h>

device_t cpufreq_dev;
struct cf_level levels[CPUFREQ_MAX_LEVELS];  // or better, malloc
int num_levels = CPUFREQ_MAX_LEVELS;

// Find cpufreq0 device pointer
cpufreq_dev = devclass_get_device(devclass_find("cpufreq"), 0);
if (cpufreq_dev == NULL)
     return error, no passive cooling possible

// Now find all possible levels
error = CPUFREQ_LEVELS(cpufreq_dev, levels, &num_levels);
if (error)
     free levels and return error, no supported freq control

// Calculate target frequency based on _TC1 and _TC2
desired_freq = ...

// Select appropriate level now, picking one that is "close enough"
for (i = 0; i < num_levels; i++) {
     if (CPUFREQ_CMP(levels[i].total_set.freq, desired_freq))
         break;
}
if (i == num_levels)
     problem, requested frequency not found..  round down to next?

// Desired level found, now switch to it
error = CPUFREQ_SET(cpufreq_dev, &levels[i], CPUFREQ_PRIO_KERN);


That is all, simple eh?  :)  The cpufreq kernel interface wraps access 
to all cpufreq hardware drivers (acpi_perf, est, p4tcc, acpi_throttle, 
etc.)  You only need to call methods on cpufreq0 and it will handle 
getting the desired frequency for you.  See "man 4 cpufreq" for details.

acpi_perf has two modes, one that supplies info only.  If your BIOS only 
supports that mode, usually another driver like est will handle the 
actual hardware.  Since cpufreq is smart and probes all possible cpu 
frequency control devices, parsing _PSL is not necessary.  cpufreq(4) 
can actually use more devices than are present in _PSL.  If needed in 
the future, acpi_perf can be linked with _PSL so that dependencies are 
known.

Similar to the above code snippet, you can get the frequency from 
cpufreq0 via the CPUFREQ_GET() method.  You shouldn't need to go through 
sysctl.

There should be no conflict with userland.  The above priority value 
(CPUFREQ_PRIO_KERN) specifies that this call overrides settings made 
previously (ie. via sysctl.)  However, cpufreq(4) saves the old setting 
so that once the cooling condition passes, CPUFREQ_SET(dev, NULL, 
CPUFREQ_PRIO_KERN) can be used to restore it.

-- 
Nate



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?42CC7E67.50401>