2008-11-23 15:38:42

by Cristiano Prisciandaro

[permalink] [raw]
Subject: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

From: Cristiano Prisciandaro <[email protected]>

The bios of the eeepc 900 exposes an acpi method that allows clocking
the cpu to 630/900 MHz. This driver allows controlling the frequency
switch through the cpufreq subsystem.

Signed-off-by: Cristiano Prisciandaro <[email protected]>

---

diff -uprN -X linux-2.6.vanilla/Documentation/dontdiff linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/eee900freq.c linux-2.6/arch/x86/kernel/cpu/cpufreq/eee900freq.c
--- linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/eee900freq.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6/arch/x86/kernel/cpu/cpufreq/eee900freq.c 2008-11-23 15:06:56.000000000 +0100
@@ -0,0 +1,232 @@
+/*
+ * Experimental cpu frequency scaling driver for the eeepc 900
+ *
+ * Copyright (C) 2008 Cristiano Prisciandaro <[email protected]>
+ *
+ * This driver is based on the (experimental) finding that the
+ * eeepc bios exposes a method to underclock the bus/cpu.
+ *
+ * It seems to work fine with the following BIOS versions:
+ * 0501, 0601, 0704 and 0802.
+ *
+ * Parts of this code are from
+ * asus_acpi.c Copyright (C) Julien Lerouge, Karol Kozimor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * BIG FAT DISCLAIMER: experimental code. Possibly *dangerous*
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/cpufreq.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+
+#define MNAME "eee900freq:"
+#define ASUS_HOTK_PREFIX "\\_SB.ATKD"
+#define ASUS_CPUFV_READ_METHOD "CFVG"
+#define ASUS_CPUFV_WRITE_METHOD "CFVS"
+
+static acpi_handle handle;
+static unsigned int cpufreq_eee900_get(unsigned int cpu);
+
+/* available frequencies */
+static struct cpufreq_frequency_table eee900freq_table[] = {
+ {0, 630000},
+ {1, 900000},
+ {0, CPUFREQ_TABLE_END}
+};
+
+struct eee900_acpi_value {
+ int frequency;
+ int value;
+};
+
+static struct eee900_acpi_value eee900_acpi_values_table[] = {
+ {630000, 1},
+ {900000, 0}
+};
+
+/* read from the acpi handle (from asus_acpi.c) */
+static int read_eee900_acpi_int(acpi_handle handle, const char *method,
+ int *val)
+{
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+ status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
+ *val = out_obj.integer.value;
+ return status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
+}
+
+/* write to the acpi handle (from asus_acpi.c) */
+static int write_eee900_acpi_int(acpi_handle handle, const char *method,
+ int val, struct acpi_buffer *output)
+{
+ struct acpi_object_list params;
+ union acpi_object in_obj;
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = val;
+ status = acpi_evaluate_object(handle, (char *)method, &params, output);
+ return status == AE_OK;
+}
+
+/* return the current frequency as in acpi */
+static unsigned int cpufreq_eee900_get(unsigned int cpu)
+{
+ int value;
+
+ if (!read_eee900_acpi_int(handle, ASUS_CPUFV_READ_METHOD, &value)) {
+ printk(KERN_WARNING MNAME
+ "unable to read current frequency from "
+ ASUS_CPUFV_READ_METHOD "\n");
+ return -EINVAL;
+ }
+
+ switch (value) {
+ case 0x200:
+ return 900000;
+ case 0x201:
+ return 630000;
+ }
+
+ return 0;
+}
+
+static void cpufreq_eee900_set_freq(unsigned int index)
+{
+ struct cpufreq_freqs freqs;
+
+ freqs.old = cpufreq_eee900_get(0);
+ freqs.new = eee900freq_table[index].frequency;
+ freqs.cpu = 0;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ if (!write_eee900_acpi_int(handle, ASUS_CPUFV_WRITE_METHOD,
+ eee900_acpi_values_table[index].value, NULL))
+ printk(KERN_WARNING "unable to set new frequency: val=%x",
+ eee900_acpi_values_table[index].value);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return;
+}
+
+static int cpufreq_eee900_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int newstate = 0;
+
+ if (cpufreq_frequency_table_target
+ (policy, &eee900freq_table[0], target_freq, relation, &newstate))
+ return -EINVAL;
+
+ cpufreq_eee900_set_freq(newstate);
+
+ return 0;
+}
+
+static int cpufreq_eee900_cpu_init(struct cpufreq_policy *policy)
+{
+
+ unsigned int cfreq;
+
+ cfreq = cpufreq_eee900_get(policy->cpu);
+
+ cpufreq_frequency_table_get_attr(eee900freq_table, policy->cpu);
+
+ /* cpuinfo and default policy values */
+ policy->cpuinfo.transition_latency = 1000000; /* assumed */
+ policy->cur = cfreq;
+
+ return cpufreq_frequency_table_cpuinfo(policy, &eee900freq_table[0]);
+}
+
+static int cpufreq_eee900_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static int cpufreq_eee900_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, &eee900freq_table[0]);
+}
+
+static struct freq_attr *eee900freq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver eee900freq_driver = {
+ .verify = cpufreq_eee900_verify,
+ .target = cpufreq_eee900_target,
+ .init = cpufreq_eee900_cpu_init,
+ .exit = cpufreq_eee900_cpu_exit,
+ .get = cpufreq_eee900_get,
+ .name = "eee900freq",
+ .owner = THIS_MODULE,
+ .attr = eee900freq_attr,
+};
+
+static int __init cpufreq_eee900_init(void)
+{
+ struct cpuinfo_x86 *c = &cpu_data(0);
+ acpi_status status;
+ int ret;
+ int test;
+
+ if (c->x86_vendor != X86_VENDOR_INTEL)
+ return -ENODEV;
+
+ status = acpi_get_handle(NULL, ASUS_HOTK_PREFIX, &handle);
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO MNAME "unable to get acpi handle.\n");
+ handle = NULL;
+ return -ENODEV;
+ }
+
+ /* check if the control method is supported */
+ if (!read_eee900_acpi_int(handle, ASUS_CPUFV_READ_METHOD, &test)) {
+ printk(KERN_INFO "Get control method test failed\n");
+ return -ENODEV;
+ }
+
+ ret = cpufreq_register_driver(&eee900freq_driver);
+
+ if (!ret)
+ printk(KERN_INFO MNAME
+ "CPU frequency scaling driver for the eeepc 900.\n");
+
+ return ret;
+}
+
+static void __exit cpufreq_eee900_exit(void)
+{
+ cpufreq_unregister_driver(&eee900freq_driver);
+ printk(KERN_INFO MNAME
+ "CPU frequency scaling driver for the eeepc 900 unregistered.\n");
+}
+
+module_init(cpufreq_eee900_init);
+module_exit(cpufreq_eee900_exit);
+
+MODULE_AUTHOR("Cristiano Prisciandaro <[email protected]>");
+MODULE_DESCRIPTION("Frequency scaling driver for the eeepc 900.");
+MODULE_LICENSE("GPL");
diff -uprN -X linux-2.6.vanilla/Documentation/dontdiff linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/Kconfig linux-2.6/arch/x86/kernel/cpu/cpufreq/Kconfig
--- linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/Kconfig 2008-11-21 00:19:22.000000000 +0100
+++ linux-2.6/arch/x86/kernel/cpu/cpufreq/Kconfig 2008-11-23 12:24:47.000000000 +0100
@@ -243,6 +243,15 @@ config X86_E_POWERSAVER

If in doubt, say N.

+config X86_CPUFREQ_EEEPC900
+ tristate "Eeepc 900 ACPI frequency scaling driver"
+ select CPU_FREQ_TABLE
+ depends on ACPI && X86_32 && EXPERIMENTAL
+ help
+ This adds the CPUFreq driver for the eeepc 900.
+
+ If in doubt, say N.
+
comment "shared options"

config X86_ACPI_CPUFREQ_PROC_INTF
diff -uprN -X linux-2.6.vanilla/Documentation/dontdiff linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/Makefile linux-2.6/arch/x86/kernel/cpu/cpufreq/Makefile
--- linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/Makefile 2008-11-21 00:19:22.000000000 +0100
+++ linux-2.6/arch/x86/kernel/cpu/cpufreq/Makefile 2008-11-23 12:24:53.000000000 +0100
@@ -14,3 +14,4 @@ obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-
obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
+obj-$(CONFIG_X86_CPUFREQ_EEEPC900) += eee900freq.o



2008-11-24 10:55:01

by Tom Hughes

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Cristiano Prisciandaro wrote:

> From: Cristiano Prisciandaro <[email protected]>
>
> The bios of the eeepc 900 exposes an acpi method that allows clocking
> the cpu to 630/900 MHz. This driver allows controlling the frequency
> switch through the cpufreq subsystem.

I should perhaps add at this point that I have an alternative patch
based on Cristiano's code, which adds this cpufreq driver to the
existing eeepc-laptop module rather than creating a separate module for it.

Personally I'm quite happy with either solution so I'll leave it to you
to decide what is the best way to go, but my patch is available if you
want it.

Tom

--
Tom Hughes ([email protected])
http://www.compton.nu/

2008-11-24 15:13:34

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Monday 24 November 2008 10:38:58 am Tom Hughes wrote:
> Cristiano Prisciandaro wrote:
> > From: Cristiano Prisciandaro <[email protected]>
> >
> > The bios of the eeepc 900 exposes an acpi method that allows clocking
> > the cpu to 630/900 MHz. This driver allows controlling the frequency
> > switch through the cpufreq subsystem.
>
> I should perhaps add at this point that I have an alternative patch
> based on Cristiano's code, which adds this cpufreq driver to the
> existing eeepc-laptop module rather than creating a separate module for it.
>
> Personally I'm quite happy with either solution so I'll leave it to you
> to decide what is the best way to go, but my patch is available if you
> want it.
Either way, shouldn't you be able to provide a dmi matching module alias:
MODULE_ALIAS("dmi:...")
for autoloading?

Or are these two cpufreq functions part of an ACPI device you could match for,
then it should get an ACPI driver?
If this ACPI device provides more functions, then these should probably also
be added to this driver.
Splitting the OS drivers the same way as BIOS splits up functionality into
ACPI devices is a good idea.

Could you paste at least the whole ACPI device in which:
#define ASUS_CPUFV_READ_METHOD "CFVG"
#define ASUS_CPUFV_WRITE_METHOD "CFVS"
sit or better point to an acpidump/dsdt output.

Thomas


2008-11-24 16:37:06

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Monday 24 November 2008 04:13:24 pm Thomas Renninger wrote:
> On Monday 24 November 2008 10:38:58 am Tom Hughes wrote:
> > Cristiano Prisciandaro wrote:
> > > From: Cristiano Prisciandaro <[email protected]>
> > >
> > > The bios of the eeepc 900 exposes an acpi method that allows clocking
> > > the cpu to 630/900 MHz. This driver allows controlling the frequency
> > > switch through the cpufreq subsystem.
> >
> > I should perhaps add at this point that I have an alternative patch
> > based on Cristiano's code, which adds this cpufreq driver to the
> > existing eeepc-laptop module rather than creating a separate module for
> > it.
> >
> > Personally I'm quite happy with either solution so I'll leave it to you
> > to decide what is the best way to go, but my patch is available if you
> > want it.
>
> Either way, shouldn't you be able to provide a dmi matching module alias:
> MODULE_ALIAS("dmi:...")
> for autoloading?
>
> Or are these two cpufreq functions part of an ACPI device you could match
> for, then it should get an ACPI driver?
Oh, they are part of this general Asus \\_SB.ATKD device, which is only
used by asus_laptop.c until now?
I don't know \\_SB.ATKD in detail, but it has not a HID to match against and
contains ASUS specific ACPI helper functions?

Looks like a growing mess in the ASUS ACPI area...

Some more questions:
Why are they providing their own cpufreq interface and not following the
spec (providing _PSS, ..)?
Could it be that you are only throttling the CPU?

Are these functions already used by the ACPI tables internally?
- could be dangerous
- could be helpful -> Is there some upper level device/interface in ASL?

Could it happen that upcoming machines provide this interface (the two ACPI
functions) and also can do real CPU frequency/volt switching, e.g. via
acpi-cpufreq?

Thomas

> If this ACPI device provides more functions, then these should probably
> also be added to this driver.
> Splitting the OS drivers the same way as BIOS splits up functionality into
> ACPI devices is a good idea.
>
> Could you paste at least the whole ACPI device in which:
> #define ASUS_CPUFV_READ_METHOD "CFVG"
> #define ASUS_CPUFV_WRITE_METHOD "CFVS"
> sit or better point to an acpidump/dsdt output.
>
> Thomas

2008-11-24 16:40:18

by Tom Hughes

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Thomas Renninger wrote:

> Could you paste at least the whole ACPI device in which:
> #define ASUS_CPUFV_READ_METHOD "CFVG"
> #define ASUS_CPUFV_WRITE_METHOD "CFVS"
> sit or better point to an acpidump/dsdt output.

There's a dump of DSDT on my Eee 900 at:

http://www.compton.nu/eee900dsdt.dsl

Tom

--
Tom Hughes ([email protected])
http://www.compton.nu/

2008-11-24 16:41:19

by Corentin Chary

[permalink] [raw]
Subject: Re: [Acpi4asus-user] [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Mon, Nov 24, 2008 at 5:36 PM, Thomas Renninger <[email protected]> wrote:
> On Monday 24 November 2008 04:13:24 pm Thomas Renninger wrote:
>> On Monday 24 November 2008 10:38:58 am Tom Hughes wrote:
>> > Cristiano Prisciandaro wrote:
>> > > From: Cristiano Prisciandaro <[email protected]>
>> > >
>> > > The bios of the eeepc 900 exposes an acpi method that allows clocking
>> > > the cpu to 630/900 MHz. This driver allows controlling the frequency
>> > > switch through the cpufreq subsystem.
>> >
>> > I should perhaps add at this point that I have an alternative patch
>> > based on Cristiano's code, which adds this cpufreq driver to the
>> > existing eeepc-laptop module rather than creating a separate module for
>> > it.
>> >
>> > Personally I'm quite happy with either solution so I'll leave it to you
>> > to decide what is the best way to go, but my patch is available if you
>> > want it.
>>
Why not just modprobe p4-clockmod ?
It already has all we want and works perfectly well.

2008-11-24 16:47:19

by Tom Hughes

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Thomas Renninger wrote:

> Oh, they are part of this general Asus \\_SB.ATKD device, which is only
> used by asus_laptop.c until now?

I believe eeepc-laptop is also accessing the same device - at least it
is calling other methods defined in the same part of the DSDT although
it doesn't seem to be using that name to reach them.

> Some more questions:
> Why are they providing their own cpufreq interface and not following the
> spec (providing _PSS, ..)?
> Could it be that you are only throttling the CPU?
>
> Are these functions already used by the ACPI tables internally?
> - could be dangerous
> - could be helpful -> Is there some upper level device/interface in ASL?
>
> Could it happen that upcoming machines provide this interface (the two ACPI
> functions) and also can do real CPU frequency/volt switching, e.g. via
> acpi-cpufreq?

Well the recent eee's are all Atom based, which I assume has proper
SpeedStep support but the early ones have a Celeron processor.

The history is that the original eee, the 701, was underclocking a
900MHz CPU at 630Mhz and in the 900 they added support for running at
full speed with the BIOS able to switch between the two speeds. I assume
it just changes the clock multiplier or something.

The 901 and later of course use the Atom and presumably work differently.

Tom

--
Tom Hughes ([email protected])
http://www.compton.nu/

2008-11-24 16:48:39

by Tom Hughes

[permalink] [raw]
Subject: Re: [Acpi4asus-user] [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Corentin Chary wrote:

> Why not just modprobe p4-clockmod ?
> It already has all we want and works perfectly well.

My understanding is p4-clockmod doesn't really change anything at all
and doesn't gain you any real benefit. I know lots of web pages tell you
to use it on the eee but everything I've read says that is nonsense.

Tom

--
Tom Hughes ([email protected])
http://www.compton.nu/

2008-11-24 16:59:18

by Corentin Chary

[permalink] [raw]
Subject: Re: [Acpi4asus-user] [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Mon, Nov 24, 2008 at 5:48 PM, Tom Hughes <[email protected]> wrote:
> Corentin Chary wrote:
>
>> Why not just modprobe p4-clockmod ?
>> It already has all we want and works perfectly well.
>
> My understanding is p4-clockmod doesn't really change anything at all and
> doesn't gain you any real benefit. I know lots of web pages tell you to use
> it on the eee but everything I've read says that is nonsense.

Just modprobe p4-clockmod
- use cpufreq to go to the lower frequency
- run something cpu intensive
- go to the higher frequency (900mghz)
- you'll see the difference

at least, it works with my eeepc 700, maybe 900 is different for that,
but it seems unlikely to me.

2008-11-24 17:08:18

by Tom Hughes

[permalink] [raw]
Subject: Re: [Acpi4asus-user] [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Corentin Chary wrote:

> Just modprobe p4-clockmod
> - use cpufreq to go to the lower frequency
> - run something cpu intensive
> - go to the higher frequency (900mghz)
> - you'll see the difference
>
> at least, it works with my eeepc 700, maybe 900 is different for that,
> but it seems unlikely to me.

Have a look at http://www.codemonkey.org.uk/projects/eeepc/ for an
explanation of what p4-clockmod does and why it isn't really changing
the speed of the processor (but does cause you to get less work done).

tom

--
Tom Hughes ([email protected])
http://www.compton.nu/

2008-11-24 19:09:36

by Cristiano Prisciandaro

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Mon, 2008-11-24 at 09:38 +0000, Tom Hughes wrote:
> Cristiano Prisciandaro wrote:
>
> > The bios of the eeepc 900 exposes an acpi method that allows clocking
> > the cpu to 630/900 MHz. This driver allows controlling the frequency
> > switch through the cpufreq subsystem.
>
> I should perhaps add at this point that I have an alternative patch
> based on Cristiano's code, which adds this cpufreq driver to the
> existing eeepc-laptop module rather than creating a separate module for it.
>
> Personally I'm quite happy with either solution so I'll leave it to you
> to decide what is the best way to go, but my patch is available if you
> want it.

If this functionality has chances to be included into the kernel then I
have no problems if as a module or integrated in eeepc-laptop.

At the time of writing this module there was just the asus-acpi one:
I preferred not to mess with it.

Cristiano


2008-11-24 23:02:33

by Cristiano Prisciandaro

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Mon, 2008-11-24 at 17:36 +0100, Thomas Renninger wrote:
> On Monday 24 November 2008 04:13:24 pm Thomas Renninger wrote:
> > On Monday 24 November 2008 10:38:58 am Tom Hughes wrote:
> > > Cristiano Prisciandaro wrote:
> > > > From: Cristiano Prisciandaro <[email protected]>
> > > >
> > > > The bios of the eeepc 900 exposes an acpi method that allows clocking
> > > > the cpu to 630/900 MHz. This driver allows controlling the frequency
> > > > switch through the cpufreq subsystem.
> > >
> > > I should perhaps add at this point that I have an alternative patch
> > > based on Cristiano's code, which adds this cpufreq driver to the
> > > existing eeepc-laptop module rather than creating a separate module for
> > > it.
> > >
> > > Personally I'm quite happy with either solution so I'll leave it to you
> > > to decide what is the best way to go, but my patch is available if you
> > > want it.
> >
> > Either way, shouldn't you be able to provide a dmi matching module alias:
> > MODULE_ALIAS("dmi:...")
> > for autoloading?
> >
> > Or are these two cpufreq functions part of an ACPI device you could match
> > for, then it should get an ACPI driver?
> Oh, they are part of this general Asus \\_SB.ATKD device, which is only
> used by asus_laptop.c until now?
> I don't know \\_SB.ATKD in detail, but it has not a HID to match against and
> contains ASUS specific ACPI helper functions?
>
> Looks like a growing mess in the ASUS ACPI area...
>
> Some more questions:
> Why are they providing their own cpufreq interface and not following the
> spec (providing _PSS, ..)?
> Could it be that you are only throttling the CPU?
This eeepc is equipped with a Celeron-M ULV 353 with no clock-varying
technology support but the frequency change seems to be achieved by
changing FSB clock and cpu voltage (method FSBA).

Before bios ver. 0501 asus provided an option to switch the operation
mode of the eeepc 900 to powersave/performance: this allowed to decide a
fixed frequency at boot (630/900 MHz).

The asus-acpi module exposed this functions into the proc FS: you could
echo 0 or 1 to /proc/acpi/asus/cpufv to change the frequency.
This is the method used in the stock xandros distribution to switch to
powersave/performance mode when the power supply gets connected or
disconnected (using an acpi script).

> Are these functions already used by the ACPI tables internally?
There are 2 methods in the DSDT where the presence of the power supply
is checked and the frequency set accordingly:

INIT (only in newer bios versions)
_Q31

but both seem to do the job just for the windoz flavour.

> - could be dangerous
As this function seem to be used by asus, I don't think it is dangerous.
Probably switching too many times per second ...

This is not a good argumentation, so please skip the next lines:
I can only say that my machine (and at least Tom's one) is still
alive after months using the module ...

> - could be helpful -> Is there some upper level device/interface in ASL?
As I said before, in the stock distribution the frequency seems to be
controlled only through the proc interface and some acpi scripts: I
don't think there is some higher level controller.

> Could it happen that upcoming machines provide this interface (the two ACPI
> functions) and also can do real CPU frequency/volt switching, e.g. via
> acpi-cpufreq?

Probably this interface is a solution specific to machines based on the
celeron M: I don't even know if other 'old' models provide the same
interface.

cristiano

2008-12-02 14:40:45

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Sun 2008-11-23 16:27:06, Cristiano Prisciandaro wrote:
> From: Cristiano Prisciandaro <[email protected]>
>
> The bios of the eeepc 900 exposes an acpi method that allows clocking
> the cpu to 630/900 MHz. This driver allows controlling the frequency
> switch through the cpufreq subsystem.

Is this really needed? Could we simply talk to the cpu directly,
without help of ACPI?

> +/* write to the acpi handle (from asus_acpi.c) */
> +static int write_eee900_acpi_int(acpi_handle handle, const char *method,
> + int val, struct acpi_buffer *output)
> +{
> + struct acpi_object_list params;
> + union acpi_object in_obj;
> + acpi_status status;
> +
> + params.count = 1;
> + params.pointer = &in_obj;
> + in_obj.type = ACPI_TYPE_INTEGER;
> + in_obj.integer.value = val;
> + status = acpi_evaluate_object(handle, (char *)method, &params, output);
> + return status == AE_OK;
> +}

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2008-12-02 16:15:42

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Sun, Nov 23, 2008 at 07:04:09PM +0100, Pavel Machek wrote:

> Is this really needed? Could we simply talk to the cpu directly,
> without help of ACPI?

No. The ACPI write ends up talking to the embedded controller and some
io ports.

--
Matthew Garrett | [email protected]

2008-12-02 20:15:07

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Tue 2008-12-02 16:15:21, Matthew Garrett wrote:
> On Sun, Nov 23, 2008 at 07:04:09PM +0100, Pavel Machek wrote:
>
> > Is this really needed? Could we simply talk to the cpu directly,
> > without help of ACPI?
>
> No. The ACPI write ends up talking to the embedded controller and some
> io ports.

Oops... I always knew that eee-s are broken by design (reporting
battery percent as mWh, etc...) but I did not realize how bad it
is. (ACPI has perfectly standard cpu frequency scaling interface, even
if it is not used too often these days....)

Sorry for the noise.
Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2008-12-03 19:27:28

by Tom Hughes

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Tom Hughes wrote:
> Cristiano Prisciandaro wrote:
>
>> From: Cristiano Prisciandaro <[email protected]>
>>
>> The bios of the eeepc 900 exposes an acpi method that allows clocking
>> the cpu to 630/900 MHz. This driver allows controlling the frequency
>> switch through the cpufreq subsystem.
>
> I should perhaps add at this point that I have an alternative patch
> based on Cristiano's code, which adds this cpufreq driver to the
> existing eeepc-laptop module rather than creating a separate module for it.

For the record, and as this discussion seems to have ground to a halt a
bit at the moment, here is my version of the eee 900 cpufreq driver:

--- kmod-eeepc-laptop-2.6.28rc5/eeepc-laptop.c 2008-11-20 09:24:41.000000000 +0000
+++ kmod-eeepc-laptop-cpufreq/eeepc-laptop.c 2008-12-03 18:59:14.000000000 +0000
@@ -25,6 +25,7 @@
#include <linux/fb.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/cpufreq.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <linux/uaccess.h>
@@ -731,6 +732,112 @@
};

/*
+ * Cpufreq
+ *
+ * Based on work by Cristiano P. <[email protected]>
+ */
+static struct cpufreq_frequency_table eeepc_cpufreq_table[] = {
+ {0, 630000},
+ {1, 900000},
+ {0, CPUFREQ_TABLE_END}
+};
+
+static unsigned int eeepc_cpufreq_get(unsigned int cpu)
+{
+ switch (get_acpi(CM_ASL_CPUFV)) {
+ case 0x200:
+ return 900000;
+ case 0x201:
+ return 630000;
+ }
+
+ return 0;
+}
+
+static void eeepc_cpufreq_set(unsigned int frequency)
+{
+ struct cpufreq_freqs freqs;
+
+ freqs.cpu = 0;
+ freqs.old = eeepc_cpufreq_get(0);
+ freqs.new = frequency;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ switch (frequency) {
+ case 900000:
+ set_acpi(CM_ASL_CPUFV, 0);
+ break;
+ case 630000:
+ set_acpi(CM_ASL_CPUFV, 1);
+ break;
+ }
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return;
+}
+
+static int eeepc_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, eeepc_cpufreq_table);
+}
+
+static int eeepc_cpufreq_target (struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int newstate = 0;
+
+ if (cpufreq_frequency_table_target(policy, eeepc_cpufreq_table,
+ target_freq, relation, &newstate))
+ return -EINVAL;
+
+ eeepc_cpufreq_set(eeepc_cpufreq_table[newstate].frequency);
+
+ return 0;
+}
+
+static int eeepc_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ if (get_acpi(CM_ASL_CPUFV) != -1)
+ {
+ policy->cpuinfo.transition_latency = 1000000;
+ policy->cur = eeepc_cpufreq_get(policy->cpu);
+
+ if (cpufreq_frequency_table_cpuinfo(policy, eeepc_cpufreq_table))
+ return -EINVAL;
+
+ cpufreq_frequency_table_get_attr(eeepc_cpufreq_table, policy->cpu);
+ }
+
+ return 0;
+}
+
+static int eeepc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+
+ return 0;
+}
+
+static struct freq_attr *eeepc_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver eeepc_cpufreq_driver = {
+ .verify = eeepc_cpufreq_verify,
+ .target = eeepc_cpufreq_target,
+ .init = eeepc_cpufreq_cpu_init,
+ .exit = eeepc_cpufreq_cpu_exit,
+ .get = eeepc_cpufreq_get,
+ .name = "eeepc",
+ .owner = THIS_MODULE,
+ .attr = eeepc_cpufreq_attr,
+};
+
+/*
* exit/init
*/
static void eeepc_backlight_exit(void)
@@ -759,10 +866,16 @@
eeepc_hwmon_device = NULL;
}

+static void eeepc_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&eeepc_cpufreq_driver);
+}
+
static void __exit eeepc_laptop_exit(void)
{
eeepc_backlight_exit();
eeepc_hwmon_exit();
+ eeepc_cpufreq_exit();
acpi_bus_unregister_driver(&eeepc_hotk_driver);
sysfs_remove_group(&platform_device->dev.kobj,
&platform_attribute_group);
@@ -810,6 +923,11 @@
return result;
}

+static int eeepc_cpufreq_init(struct device *dev)
+{
+ return cpufreq_register_driver(&eeepc_cpufreq_driver);
+}
+
static int __init eeepc_laptop_init(void)
{
struct device *dev;
@@ -837,6 +955,9 @@
result = eeepc_hwmon_init(dev);
if (result)
goto fail_hwmon;
+ result = eeepc_cpufreq_init(dev);
+ if (result)
+ goto fail_cpufreq;
/* Register platform stuff */
result = platform_driver_register(&platform_driver);
if (result)
@@ -861,6 +982,8 @@
fail_platform_device1:
platform_driver_unregister(&platform_driver);
fail_platform_driver:
+ eeepc_cpufreq_exit();
+fail_cpufreq:
eeepc_hwmon_exit();
fail_hwmon:
eeepc_backlight_exit();


Tom

--
Tom Hughes ([email protected])
http://www.compton.nu/

2008-12-04 01:57:18

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Hi,

On Wednesday 03 December 2008 08:26:48 pm Tom Hughes wrote:
> Tom Hughes wrote:
> > Cristiano Prisciandaro wrote:
> >> From: Cristiano Prisciandaro <[email protected]>
> >>
> >> The bios of the eeepc 900 exposes an acpi method that allows clocking
> >> the cpu to 630/900 MHz. This driver allows controlling the frequency
> >> switch through the cpufreq subsystem.
> >
> > I should perhaps add at this point that I have an alternative patch
> > based on Cristiano's code, which adds this cpufreq driver to the
> > existing eeepc-laptop module rather than creating a separate module for
> > it.
>
> For the record, and as this discussion seems to have ground to a halt a
> bit at the moment, here is my version of the eee 900 cpufreq driver:

The biggest problem I see with these "special" ACPI cpufreq interface is:
Can there be Asus/eeepcs which provide these ACPI functions (maybe dummies on
future machines?), but can still be switched via the spec conform and more
efficient acpi-cpufreq driver via PSS tables?

Then it is pure luck which one will win, there can only be one cpufreq driver.

BTW: Have you tried out how much power (or at least battery life time) you
win?

Thomas
>
> --- kmod-eeepc-laptop-2.6.28rc5/eeepc-laptop.c 2008-11-20
> 09:24:41.000000000 +0000 +++
> kmod-eeepc-laptop-cpufreq/eeepc-laptop.c 2008-12-03 18:59:14.000000000
> +0000 @@ -25,6 +25,7 @@
> #include <linux/fb.h>
> #include <linux/hwmon.h>
> #include <linux/hwmon-sysfs.h>
> +#include <linux/cpufreq.h>
> #include <acpi/acpi_drivers.h>
> #include <acpi/acpi_bus.h>
> #include <linux/uaccess.h>
> @@ -731,6 +732,112 @@
> };
>
> /*
> + * Cpufreq
> + *
> + * Based on work by Cristiano P. <[email protected]>
> + */
> +static struct cpufreq_frequency_table eeepc_cpufreq_table[] = {
> + {0, 630000},
> + {1, 900000},
> + {0, CPUFREQ_TABLE_END}
> +};
> +
> +static unsigned int eeepc_cpufreq_get(unsigned int cpu)
> +{
> + switch (get_acpi(CM_ASL_CPUFV)) {
> + case 0x200:
> + return 900000;
> + case 0x201:
> + return 630000;
> + }
> +
> + return 0;
> +}
> +
> +static void eeepc_cpufreq_set(unsigned int frequency)
> +{
> + struct cpufreq_freqs freqs;
> +
> + freqs.cpu = 0;
> + freqs.old = eeepc_cpufreq_get(0);
> + freqs.new = frequency;
> +
> + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +
> + switch (frequency) {
> + case 900000:
> + set_acpi(CM_ASL_CPUFV, 0);
> + break;
> + case 630000:
> + set_acpi(CM_ASL_CPUFV, 1);
> + break;
> + }
> +
> + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> +
> + return;
> +}
> +
> +static int eeepc_cpufreq_verify(struct cpufreq_policy *policy)
> +{
> + return cpufreq_frequency_table_verify(policy, eeepc_cpufreq_table);
> +}
> +
> +static int eeepc_cpufreq_target (struct cpufreq_policy *policy,
> + unsigned int target_freq,
> + unsigned int relation)
> +{
> + unsigned int newstate = 0;
> +
> + if (cpufreq_frequency_table_target(policy, eeepc_cpufreq_table,
> + target_freq, relation, &newstate))
> + return -EINVAL;
> +
> + eeepc_cpufreq_set(eeepc_cpufreq_table[newstate].frequency);
> +
> + return 0;
> +}
> +
> +static int eeepc_cpufreq_cpu_init(struct cpufreq_policy *policy)
> +{
> + if (get_acpi(CM_ASL_CPUFV) != -1)
> + {
> + policy->cpuinfo.transition_latency = 1000000;
> + policy->cur = eeepc_cpufreq_get(policy->cpu);
> +
> + if (cpufreq_frequency_table_cpuinfo(policy, eeepc_cpufreq_table))
> + return -EINVAL;
> +
> + cpufreq_frequency_table_get_attr(eeepc_cpufreq_table, policy->cpu);
> + }
> +
> + return 0;
> +}
> +
> +static int eeepc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
> +{
> + cpufreq_frequency_table_put_attr(policy->cpu);
> +
> + return 0;
> +}
> +
> +static struct freq_attr *eeepc_cpufreq_attr[] = {
> + &cpufreq_freq_attr_scaling_available_freqs,
> + NULL,
> +};
> +
> +static struct cpufreq_driver eeepc_cpufreq_driver = {
> + .verify = eeepc_cpufreq_verify,
> + .target = eeepc_cpufreq_target,
> + .init = eeepc_cpufreq_cpu_init,
> + .exit = eeepc_cpufreq_cpu_exit,
> + .get = eeepc_cpufreq_get,
> + .name = "eeepc",
> + .owner = THIS_MODULE,
> + .attr = eeepc_cpufreq_attr,
> +};
> +
> +/*
> * exit/init
> */
> static void eeepc_backlight_exit(void)
> @@ -759,10 +866,16 @@
> eeepc_hwmon_device = NULL;
> }
>
> +static void eeepc_cpufreq_exit(void)
> +{
> + cpufreq_unregister_driver(&eeepc_cpufreq_driver);
> +}
> +
> static void __exit eeepc_laptop_exit(void)
> {
> eeepc_backlight_exit();
> eeepc_hwmon_exit();
> + eeepc_cpufreq_exit();
> acpi_bus_unregister_driver(&eeepc_hotk_driver);
> sysfs_remove_group(&platform_device->dev.kobj,
> &platform_attribute_group);
> @@ -810,6 +923,11 @@
> return result;
> }
>
> +static int eeepc_cpufreq_init(struct device *dev)
> +{
> + return cpufreq_register_driver(&eeepc_cpufreq_driver);
> +}
> +
> static int __init eeepc_laptop_init(void)
> {
> struct device *dev;
> @@ -837,6 +955,9 @@
> result = eeepc_hwmon_init(dev);
> if (result)
> goto fail_hwmon;
> + result = eeepc_cpufreq_init(dev);
> + if (result)
> + goto fail_cpufreq;
> /* Register platform stuff */
> result = platform_driver_register(&platform_driver);
> if (result)
> @@ -861,6 +982,8 @@
> fail_platform_device1:
> platform_driver_unregister(&platform_driver);
> fail_platform_driver:
> + eeepc_cpufreq_exit();
> +fail_cpufreq:
> eeepc_hwmon_exit();
> fail_hwmon:
> eeepc_backlight_exit();
>
>
> Tom

2008-12-05 23:06:00

by Tom Hughes

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Thomas Renninger wrote:

> The biggest problem I see with these "special" ACPI cpufreq interface is:
> Can there be Asus/eeepcs which provide these ACPI functions (maybe dummies on
> future machines?), but can still be switched via the spec conform and more
> efficient acpi-cpufreq driver via PSS tables?

So should we tie this driver to particular DMI signature(s) then? As far
as I know it is only useful for the Eee 900 and possibly the 701 when
running later BIOSes.

> BTW: Have you tried out how much power (or at least battery life time) you
> win?

Running with wifi and the screen off, and the CPU busy (doing m5sum of
/dev/zero) I get 2:37 run time at 900MHz and 3:09 at 630MHz so the
increase in run time is about 20% on that test.

Tom

--
Tom Hughes ([email protected])
http://www.compton.nu/

2008-12-06 16:36:15

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Fri, Dec 05, 2008 at 11:05:39PM +0000, Tom Hughes wrote:
> Thomas Renninger wrote:
>
> >The biggest problem I see with these "special" ACPI cpufreq interface is:
> >Can there be Asus/eeepcs which provide these ACPI functions (maybe dummies
> >on
> >future machines?), but can still be switched via the spec conform and more
> >efficient acpi-cpufreq driver via PSS tables?
>
> So should we tie this driver to particular DMI signature(s) then? As far
> as I know it is only useful for the Eee 900 and possibly the 701 when
> running later BIOSes.

It appears to be implemented in the 900 and 901 BIOSes as well, so some
kind of limitation is probably needed. The best approach would probably
to check whether the CPU has the EST flag. Just do something like:

struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu);

if (cpu->x86_vendor != X86_VENDOR_INTEL || cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV

at the top of the cpufreq init code. That way you'll refuse to bind on
anything that implements speedstep and acpi-cpufreq can be used instead.

> Running with wifi and the screen off, and the CPU busy (doing m5sum of
> /dev/zero) I get 2:37 run time at 900MHz and 3:09 at 630MHz so the
> increase in run time is about 20% on that test.

My only concern about this is that implementing it via cpufreq means
that on most distributions you'll end up with ondamend running the CPU.
This makes sense on systems where the cpu scaling drops the voltage, but
that isn't the case here as far as I can tell. This may result in some
workloads now having lower battery lives than they did previously. I'll
try to do some experimentation next week.

Other than that, this patch looks good. I think it makes sense to
integrate it into eeepc-laptop.

--
Matthew Garrett | [email protected]

2008-12-07 15:55:47

by Tom Hughes

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Matthew Garrett wrote:

> It appears to be implemented in the 900 and 901 BIOSes as well, so some
> kind of limitation is probably needed. The best approach would probably
> to check whether the CPU has the EST flag. Just do something like:
>
> struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu);
>
> if (cpu->x86_vendor != X86_VENDOR_INTEL || cpu_has(cpu, X86_FEATURE_EST))
> return -ENODEV
>
> at the top of the cpufreq init code. That way you'll refuse to bind on
> anything that implements speedstep and acpi-cpufreq can be used instead.

Sounds like a good idea - here's a new version with that check added:

--- kmod-eeepc-laptop-2.6.28rc5/eeepc-laptop.c 2008-11-20 09:24:41.000000000 +0000
+++ kmod-eeepc-laptop-cpufreq/eeepc-laptop.c 2008-12-07 15:54:07.000000000 +0000
@@ -25,6 +25,7 @@
#include <linux/fb.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/cpufreq.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <linux/uaccess.h>
@@ -731,6 +732,118 @@
};

/*
+ * Cpufreq
+ *
+ * Based on work by Cristiano P. <[email protected]>
+ */
+static struct cpufreq_frequency_table eeepc_cpufreq_table[] = {
+ {0, 630000},
+ {1, 900000},
+ {0, CPUFREQ_TABLE_END}
+};
+
+static unsigned int eeepc_cpufreq_get(unsigned int cpu)
+{
+ switch (get_acpi(CM_ASL_CPUFV)) {
+ case 0x200:
+ return 900000;
+ case 0x201:
+ return 630000;
+ }
+
+ return 0;
+}
+
+static void eeepc_cpufreq_set(unsigned int frequency)
+{
+ struct cpufreq_freqs freqs;
+
+ freqs.cpu = 0;
+ freqs.old = eeepc_cpufreq_get(0);
+ freqs.new = frequency;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ switch (frequency) {
+ case 900000:
+ set_acpi(CM_ASL_CPUFV, 0);
+ break;
+ case 630000:
+ set_acpi(CM_ASL_CPUFV, 1);
+ break;
+ }
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return;
+}
+
+static int eeepc_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, eeepc_cpufreq_table);
+}
+
+static int eeepc_cpufreq_target (struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int newstate = 0;
+
+ if (cpufreq_frequency_table_target(policy, eeepc_cpufreq_table,
+ target_freq, relation, &newstate))
+ return -EINVAL;
+
+ eeepc_cpufreq_set(eeepc_cpufreq_table[newstate].frequency);
+
+ return 0;
+}
+
+static int eeepc_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu);
+
+ /* Defer to acpi-cpufreq if this CPU has SpeedStep support */
+ if (cpu->x86_vendor != X86_VENDOR_INTEL || cpu_has(cpu, X86_FEATURE_EST))
+ return -ENODEV;
+
+ if (get_acpi(CM_ASL_CPUFV) < 0)
+ return -ENODEV;
+
+ policy->cpuinfo.transition_latency = 1000000;
+ policy->cur = eeepc_cpufreq_get(policy->cpu);
+
+ if (cpufreq_frequency_table_cpuinfo(policy, eeepc_cpufreq_table))
+ return -EINVAL;
+
+ cpufreq_frequency_table_get_attr(eeepc_cpufreq_table, policy->cpu);
+
+ return 0;
+}
+
+static int eeepc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+
+ return 0;
+}
+
+static struct freq_attr *eeepc_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver eeepc_cpufreq_driver = {
+ .verify = eeepc_cpufreq_verify,
+ .target = eeepc_cpufreq_target,
+ .init = eeepc_cpufreq_cpu_init,
+ .exit = eeepc_cpufreq_cpu_exit,
+ .get = eeepc_cpufreq_get,
+ .name = "eeepc",
+ .owner = THIS_MODULE,
+ .attr = eeepc_cpufreq_attr,
+};
+
+/*
* exit/init
*/
static void eeepc_backlight_exit(void)
@@ -759,10 +872,16 @@
eeepc_hwmon_device = NULL;
}

+static void eeepc_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&eeepc_cpufreq_driver);
+}
+
static void __exit eeepc_laptop_exit(void)
{
eeepc_backlight_exit();
eeepc_hwmon_exit();
+ eeepc_cpufreq_exit();
acpi_bus_unregister_driver(&eeepc_hotk_driver);
sysfs_remove_group(&platform_device->dev.kobj,
&platform_attribute_group);
@@ -810,6 +929,11 @@
return result;
}

+static int eeepc_cpufreq_init(struct device *dev)
+{
+ return cpufreq_register_driver(&eeepc_cpufreq_driver);
+}
+
static int __init eeepc_laptop_init(void)
{
struct device *dev;
@@ -837,6 +961,9 @@
result = eeepc_hwmon_init(dev);
if (result)
goto fail_hwmon;
+ result = eeepc_cpufreq_init(dev);
+ if (result)
+ goto fail_cpufreq;
/* Register platform stuff */
result = platform_driver_register(&platform_driver);
if (result)
@@ -861,6 +988,8 @@
fail_platform_device1:
platform_driver_unregister(&platform_driver);
fail_platform_driver:
+ eeepc_cpufreq_exit();
+fail_cpufreq:
eeepc_hwmon_exit();
fail_hwmon:
eeepc_backlight_exit();


Tom

--
Tom Hughes ([email protected])
http://www.compton.nu/

2008-12-09 12:36:41

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Sun 2008-12-07 15:55:00, Tom Hughes wrote:
> Matthew Garrett wrote:
>
>> It appears to be implemented in the 900 and 901 BIOSes as well, so some
>> kind of limitation is probably needed. The best approach would probably
>> to check whether the CPU has the EST flag. Just do something like:
>>
>> struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu);
>>
>> if (cpu->x86_vendor != X86_VENDOR_INTEL || cpu_has(cpu, X86_FEATURE_EST))
>> return -ENODEV
>>
>> at the top of the cpufreq init code. That way you'll refuse to bind on
>> anything that implements speedstep and acpi-cpufreq can be used
>> instead.
>
> Sounds like a good idea - here's a new version with that check added:

Whitespace damaged and needs signed-off-by; otherwise looks ok to me.

> --- kmod-eeepc-laptop-2.6.28rc5/eeepc-laptop.c 2008-11-20 09:24:41.000000000 +0000
> +++ kmod-eeepc-laptop-cpufreq/eeepc-laptop.c 2008-12-07 15:54:07.000000000 +0000
> @@ -25,6 +25,7 @@
> #include <linux/fb.h>
> #include <linux/hwmon.h>
> #include <linux/hwmon-sysfs.h>
> +#include <linux/cpufreq.h>
> #include <acpi/acpi_drivers.h>
> #include <acpi/acpi_bus.h>
> #include <linux/uaccess.h>
> @@ -731,6 +732,118 @@
> };
>
> /*
> + * Cpufreq
> + *
> + * Based on work by Cristiano P. <[email protected]>
> + */
> +static struct cpufreq_frequency_table eeepc_cpufreq_table[] = {
> + {0, 630000},
> + {1, 900000},
> + {0, CPUFREQ_TABLE_END}
> +};
> +
> +static unsigned int eeepc_cpufreq_get(unsigned int cpu)
> +{
> + switch (get_acpi(CM_ASL_CPUFV)) {
> + case 0x200:
> + return 900000;
> + case 0x201:
> + return 630000;
> + }
> +
> + return 0;
> +}
> +
> +static void eeepc_cpufreq_set(unsigned int frequency)
> +{
> + struct cpufreq_freqs freqs;
> +
> + freqs.cpu = 0;
> + freqs.old = eeepc_cpufreq_get(0);
> + freqs.new = frequency;
> +
> + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +
> + switch (frequency) {
> + case 900000:
> + set_acpi(CM_ASL_CPUFV, 0);
> + break;
> + case 630000:
> + set_acpi(CM_ASL_CPUFV, 1);
> + break;
> + }
> +
> + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> +
> + return;
> +}
> +
> +static int eeepc_cpufreq_verify(struct cpufreq_policy *policy)
> +{
> + return cpufreq_frequency_table_verify(policy, eeepc_cpufreq_table);
> +}
> +
> +static int eeepc_cpufreq_target (struct cpufreq_policy *policy,
> + unsigned int target_freq,
> + unsigned int relation)
> +{
> + unsigned int newstate = 0;
> +
> + if (cpufreq_frequency_table_target(policy, eeepc_cpufreq_table,
> + target_freq, relation, &newstate))
> + return -EINVAL;
> +
> + eeepc_cpufreq_set(eeepc_cpufreq_table[newstate].frequency);
> +
> + return 0;
> +}
> +
> +static int eeepc_cpufreq_cpu_init(struct cpufreq_policy *policy)
> +{
> + struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu);
> +
> + /* Defer to acpi-cpufreq if this CPU has SpeedStep support */
> + if (cpu->x86_vendor != X86_VENDOR_INTEL || cpu_has(cpu, X86_FEATURE_EST))
> + return -ENODEV;
> +
> + if (get_acpi(CM_ASL_CPUFV) < 0)
> + return -ENODEV;
> +
> + policy->cpuinfo.transition_latency = 1000000;
> + policy->cur = eeepc_cpufreq_get(policy->cpu);
> +
> + if (cpufreq_frequency_table_cpuinfo(policy, eeepc_cpufreq_table))
> + return -EINVAL;
> +
> + cpufreq_frequency_table_get_attr(eeepc_cpufreq_table, policy->cpu);
> +
> + return 0;
> +}
> +
> +static int eeepc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
> +{
> + cpufreq_frequency_table_put_attr(policy->cpu);
> +
> + return 0;
> +}
> +
> +static struct freq_attr *eeepc_cpufreq_attr[] = {
> + &cpufreq_freq_attr_scaling_available_freqs,
> + NULL,
> +};
> +
> +static struct cpufreq_driver eeepc_cpufreq_driver = {
> + .verify = eeepc_cpufreq_verify,
> + .target = eeepc_cpufreq_target,
> + .init = eeepc_cpufreq_cpu_init,
> + .exit = eeepc_cpufreq_cpu_exit,
> + .get = eeepc_cpufreq_get,
> + .name = "eeepc",
> + .owner = THIS_MODULE,
> + .attr = eeepc_cpufreq_attr,
> +};
> +
> +/*
> * exit/init
> */
> static void eeepc_backlight_exit(void)
> @@ -759,10 +872,16 @@
> eeepc_hwmon_device = NULL;
> }
>
> +static void eeepc_cpufreq_exit(void)
> +{
> + cpufreq_unregister_driver(&eeepc_cpufreq_driver);
> +}
> +
> static void __exit eeepc_laptop_exit(void)
> {
> eeepc_backlight_exit();
> eeepc_hwmon_exit();
> + eeepc_cpufreq_exit();
> acpi_bus_unregister_driver(&eeepc_hotk_driver);
> sysfs_remove_group(&platform_device->dev.kobj,
> &platform_attribute_group);
> @@ -810,6 +929,11 @@
> return result;
> }
>
> +static int eeepc_cpufreq_init(struct device *dev)
> +{
> + return cpufreq_register_driver(&eeepc_cpufreq_driver);
> +}
> +
> static int __init eeepc_laptop_init(void)
> {
> struct device *dev;
> @@ -837,6 +961,9 @@
> result = eeepc_hwmon_init(dev);
> if (result)
> goto fail_hwmon;
> + result = eeepc_cpufreq_init(dev);
> + if (result)
> + goto fail_cpufreq;
> /* Register platform stuff */
> result = platform_driver_register(&platform_driver);
> if (result)
> @@ -861,6 +988,8 @@
> fail_platform_device1:
> platform_driver_unregister(&platform_driver);
> fail_platform_driver:
> + eeepc_cpufreq_exit();
> +fail_cpufreq:
> eeepc_hwmon_exit();
> fail_hwmon:
> eeepc_backlight_exit();
>
>
> Tom
>

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2009-03-16 04:24:34

by Len Brown

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver


On Tue, 2 Dec 2008, Pavel Machek wrote:

> On Tue 2008-12-02 16:15:21, Matthew Garrett wrote:
> > On Sun, Nov 23, 2008 at 07:04:09PM +0100, Pavel Machek wrote:
> >
> > > Is this really needed? Could we simply talk to the cpu directly,
> > > without help of ACPI?
> >
> > No. The ACPI write ends up talking to the embedded controller and some
> > io ports.
>
> Oops... I always knew that eee-s are broken by design (reporting
> battery percent as mWh, etc...) but I did not realize how bad it
> is. (ACPI has perfectly standard cpu frequency scaling interface, even
> if it is not used too often these days....)

Huh?

What cpufreq driver is deployed more broadly than acpi-cpufreq?
AFAIK, Linux uses it on nearly every ACPI compliant Intel-based
system that has frequency scaling.

-Len

2009-03-16 08:27:21

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Mon 2009-03-16 00:24:18, Len Brown wrote:
>
> On Tue, 2 Dec 2008, Pavel Machek wrote:
>
> > On Tue 2008-12-02 16:15:21, Matthew Garrett wrote:
> > > On Sun, Nov 23, 2008 at 07:04:09PM +0100, Pavel Machek wrote:
> > >
> > > > Is this really needed? Could we simply talk to the cpu directly,
> > > > without help of ACPI?
> > >
> > > No. The ACPI write ends up talking to the embedded controller and some
> > > io ports.
> >
> > Oops... I always knew that eee-s are broken by design (reporting
> > battery percent as mWh, etc...) but I did not realize how bad it
> > is. (ACPI has perfectly standard cpu frequency scaling interface, even
> > if it is not used too often these days....)
>
> Huh?
>
> What cpufreq driver is deployed more broadly than acpi-cpufreq?
> AFAIK, Linux uses it on nearly every ACPI compliant Intel-based
> system that has frequency scaling.

Problem seems to be that eee uses custom ACPI methods
(switch_to_fast_clock(0/1)-like), not anything acpi-cpufreq could
drive... Broken by design :-(.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2009-03-17 08:31:10

by Fabio Comolli

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Well, I see that this thread has resumed after three months of being idle.
Is there a chance that either Cristiano's or Tom's version can be included?

By the way, I currently run my eeepc 900 with cpufreq disabled.
Looking at the patch, with Tom's mods to eeepc_laptop I could do the
same, am I right? I see only an include for cpufreq.h and nothing
else.

Thanks,
Fabio



On Mon, Mar 16, 2009 at 9:29 AM, Pavel Machek <[email protected]> wrote:
> On Mon 2009-03-16 00:24:18, Len Brown wrote:
>>
>> On Tue, 2 Dec 2008, Pavel Machek wrote:
>>
>> > On Tue 2008-12-02 16:15:21, Matthew Garrett wrote:
>> > > On Sun, Nov 23, 2008 at 07:04:09PM +0100, Pavel Machek wrote:
>> > >
>> > > > Is this really needed? Could we simply talk to the cpu directly,
>> > > > without help of ACPI?
>> > >
>> > > No. The ACPI write ends up talking to the embedded controller and some
>> > > io ports.
>> >
>> > Oops... I always knew that eee-s are broken by design (reporting
>> > battery percent as mWh, etc...) but I did not realize how bad it
>> > is. (ACPI has perfectly standard cpu frequency scaling interface, even
>> > if it is not used too often these days....)
>>
>> Huh?
>>
>> What cpufreq driver is deployed more broadly than acpi-cpufreq?
>> AFAIK, Linux uses it on nearly every ACPI compliant Intel-based
>> system that has frequency scaling.
>
> Problem seems to be that eee uses custom ACPI methods
> (switch_to_fast_clock(0/1)-like), not anything acpi-cpufreq could
> drive... Broken by design :-(.
>                                                                        Pavel
> --
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

2009-03-17 08:59:31

by Fabio Comolli

[permalink] [raw]
Subject: Re: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Well, replying to myself: it doesn't even compile with CONFIG_CPU_FREQ=n

On Tue, Mar 17, 2009 at 9:30 AM, Fabio Comolli <[email protected]> wrote:
> Well, I see that this thread has resumed after three months of being idle.
> Is there a chance that either Cristiano's or Tom's version can be included?
>
> By the way, I currently run my eeepc 900 with cpufreq disabled.
> Looking at the patch, with Tom's mods to eeepc_laptop I could do the
> same, am I right? I see only an include for cpufreq.h and nothing
> else.
>
> Thanks,
> Fabio
>
>
>
> On Mon, Mar 16, 2009 at 9:29 AM, Pavel Machek <[email protected]> wrote:
>> On Mon 2009-03-16 00:24:18, Len Brown wrote:
>>>
>>> On Tue, 2 Dec 2008, Pavel Machek wrote:
>>>
>>> > On Tue 2008-12-02 16:15:21, Matthew Garrett wrote:
>>> > > On Sun, Nov 23, 2008 at 07:04:09PM +0100, Pavel Machek wrote:
>>> > >
>>> > > > Is this really needed? Could we simply talk to the cpu directly,
>>> > > > without help of ACPI?
>>> > >
>>> > > No. The ACPI write ends up talking to the embedded controller and some
>>> > > io ports.
>>> >
>>> > Oops... I always knew that eee-s are broken by design (reporting
>>> > battery percent as mWh, etc...) but I did not realize how bad it
>>> > is. (ACPI has perfectly standard cpu frequency scaling interface, even
>>> > if it is not used too often these days....)
>>>
>>> Huh?
>>>
>>> What cpufreq driver is deployed more broadly than acpi-cpufreq?
>>> AFAIK, Linux uses it on nearly every ACPI compliant Intel-based
>>> system that has frequency scaling.
>>
>> Problem seems to be that eee uses custom ACPI methods
>> (switch_to_fast_clock(0/1)-like), not anything acpi-cpufreq could
>> drive... Broken by design :-(.
>>                                                                        Pavel
>> --
>> (english) http://www.livejournal.com/~pavelmachek
>> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to [email protected]
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
>>
>

2009-04-05 07:43:59

by Corentin Chary

[permalink] [raw]
Subject: Re: [Acpi4asus-user] [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

>> Could it happen that upcoming machines provide this interface (the two ACPI
>> functions) and also can do real CPU frequency/volt switching, e.g. via
>> acpi-cpufreq?
>
> Probably this interface is a solution specific to machines based on the
> celeron M: I don't even know if other 'old' models provide the same
> interface.

Hi,
We I just received another patch for that (adding a cpufv file in
sysfs) and I don't really know what to do.

As Grigori Goronzy said, using cpufreq in not a good idea:

> 1) dynamic governors like "ondemand" or "conservative" are not suitable
> for SHE. It's possible to avoid usage of these by specifying a long
> (e.g. UINT_MAX) transition latency. However, the fallback governor is
> "performance" which isn't a good idea either, because it'll use the
> overclock setting always. For SHE, the default should be the "normal",
> non-overclocked frequency.
>
> 2) The SHE ACPI interface doesn't expose the clock frequencies. I'm
> using 750 / 1000 / 1500 KHz at the moment, but that's hacky. cpufreq
> does not support performance points with names, such as "powersave",
> "normal", "performance", etc.
>
> 3) It looks like it is impossible to use more than one cpufreq driver
> per CPU. This effectively means you can either use the regular ACPI
> frequency scaling, which switches between multipliers, or SHE. That's
> unacceptable. SHE is not intended to replace the regular frequency
> scaling, but to complement it.

But adding another specific file for eeepc seems ugly too.
Does someone have a great idea to solve that ?

Thanks
--
Corentin Chary
http://xf.iksaif.net

2009-04-05 10:21:26

by Matthew Garrett

[permalink] [raw]
Subject: Re: [Acpi4asus-user] [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

On Sun, Apr 05, 2009 at 09:43:40AM +0200, Corentin Chary wrote:
> >> Could it happen that upcoming machines provide this interface (the two ACPI
> >> functions) and also can do real CPU frequency/volt switching, e.g. via
> >> acpi-cpufreq?
> >
> > Probably this interface is a solution specific to machines based on the
> > celeron M: I don't even know if other 'old' models provide the same
> > interface.
>
> Hi,
> We I just received another patch for that (adding a cpufv file in
> sysfs) and I don't really know what to do.
>
> As Grigori Goronzy said, using cpufreq in not a good idea:

I'm not sure I agree. It's clear that ondemand and conservative aren't
sensible choices with the driver, but beyond that...

> > 3) It looks like it is impossible to use more than one cpufreq driver
> > per CPU. This effectively means you can either use the regular ACPI
> > frequency scaling, which switches between multipliers, or SHE. That's
> > unacceptable. SHE is not intended to replace the regular frequency
> > scaling, but to complement it.

I don't think there's a terribly good reason to use the SHE methods if
the CPU supports speedstep. 945 will automatically drop the frontside
bus in the deepest P states. I'd be surprised if it gave any real world
benefits on the atom based systems.

--
Matthew Garrett | [email protected]

2009-04-05 11:45:12

by Grigori Goronzy

[permalink] [raw]
Subject: Re: [Acpi4asus-user] [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver

Matthew Garrett wrote:
> I don't think there's a terribly good reason to use the SHE methods if
> the CPU supports speedstep. 945 will automatically drop the frontside
> bus in the deepest P states. I'd be surprised if it gave any real world
> benefits on the atom based systems.
>

It does make quite a difference, especially because the chipset and CPU
are undervolted in the "powersave" preset. Also, SHE offers a slight
overclock (with the "performance" preset) which cannot be achieved with
mere multiplier switching. This is all guaranteed to be safe by Asus.

On my Eee PC 901, the idle power consumption drops from about 7W to 5.8W
when switching from "normal" to "powersave". That's about 15%. Under
load the benefit seems to be even greater.

I'm the author of a program called eee-control, which currently uses
another method to change FSB and voltage. It directly communicates with
the PLL controller over SMBus and with the embedded controller through
some I/O ports. This method works, but is not very safe and very
hardware specific. The ACPI interface of Asus' SHE abstracts all the
hardware differences away and thus would be preferred.
Anyway, my point is: my experience and reports by users show that the
difference is *huge*.

Regards,
Grigori