I'm running an MOTD (Mobile on the Desktop) rig, so no battery. The T7400, just like therafelbev wrote:Did you manage to get a noticable difference in battery life? Do you have a measurement in watts on the different typical power consumption?
I haven't completely researched this, but I believe that acpi-cpufreq obtainsWhoopie wrote:Hi,
why does acpi-cpufreq report other default values then speedstep-centrino?
<snip tables>
Best regards,
Whoopie
Code: Select all
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
1866000 1600000 1333000 1066000 800000
The ratio of power usages of the CPU only between undervolted and stock should roughly be equal to the square of the ratio of core voltages.rafelbev wrote:Do you have a measurement in watts on the different typical power consumption?
If we assume all the power usage at idle is due to other things than the CPU (not true, the CPU still uses some power at idle, but it's hard to quantify from "wall outlet" measurements), the CPU part of the power usage dropped from 98-56=42 W to 85-56=29 W. Power ratio is 29/42=0.69, and square of voltage ratio is (1.02/1.21)^2=0.71. That's reasonably close to the theory.b3nbranch wrote:no change at idle (56 watts measured by a kill-a-watt meter at the AC outlet) ... the system's power draw dropped from 98w to 85w, with the CPU running at about 1.02v rather than 1.21v.
Code: Select all
--- acpi-cpufreq_orig.c 2007-05-13 20:55:48.000000000 +0200
+++ acpi-cpufreq.c 2007-05-21 15:30:01.000000000 +0200
@@ -57,6 +57,8 @@
};
#define INTEL_MSR_RANGE (0xffff)
+#define INTEL_MSR_FREQUENCY (0xff00)
+#define INTEL_MSR_VOLTAGE (0x00ff)
#define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1)
struct acpi_cpufreq_data {
@@ -69,6 +71,7 @@
static struct acpi_cpufreq_data *drv_data[NR_CPUS];
static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
+static acpi_integer *original_acpi_data_control[NR_CPUS];
static struct cpufreq_driver acpi_cpufreq_driver;
@@ -104,11 +107,11 @@
int i;
struct acpi_processor_performance *perf;
- msr &= INTEL_MSR_RANGE;
+ msr &= INTEL_MSR_FREQUENCY;
perf = data->acpi_data;
for (i=0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
- if (msr == perf->states[data->freq_table[i].index].status)
+ if (msr == (perf->states[data->freq_table[i].index].status & INTEL_MSR_FREQUENCY))
return data->freq_table[i].frequency;
}
return data->freq_table[0].frequency;
@@ -668,7 +671,7 @@
data->max_freq = perf->states[0].core_frequency * 1000;
/* table init */
for (i=0; i<perf->state_count; i++) {
- if (i>0 && perf->states[i].core_frequency ==
+ if (i>0 && perf->states[i].core_frequency >=
perf->states[i-1].core_frequency)
continue;
@@ -749,6 +752,8 @@
acpi_processor_unregister_performance(data->acpi_data,
policy->cpu);
kfree(data);
+ kfree(original_acpi_data_control[policy->cpu]);
+ original_acpi_data_control[policy->cpu] = NULL;
}
return 0;
@@ -765,8 +770,119 @@
return 0;
}
+static ssize_t show_freq_voltages(struct cpufreq_policy *policy, char *buf)
+{
+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
+ struct acpi_processor_performance *perf;
+ unsigned int i;
+ unsigned int voltage;
+ ssize_t count = 0;
+
+ if (unlikely(data == NULL ||
+ data->acpi_data == NULL || data->freq_table == NULL)) {
+ return -ENODEV;
+ }
+
+ perf = data->acpi_data;
+
+ /* show space separated list of current voltages */
+ for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ voltage = perf->states[data->freq_table[i].index].control;
+ voltage = 700 + ((voltage & INTEL_MSR_VOLTAGE) << 4);
+ count += sprintf(&buf[count], "%u ", voltage);
+ }
+ count += sprintf(&buf[count], "\n");
+
+ return count;
+}
+
+static ssize_t store_freq_voltages(struct cpufreq_policy *policy, const char *buf, size_t count)
+{
+ unsigned int cpu = policy->cpu;
+ struct acpi_cpufreq_data *data = drv_data[cpu];
+ struct acpi_processor_performance *perf;
+ unsigned int i, j;
+ unsigned int voltage;
+ unsigned int voltage_index, original_index;
+ const char *curr_buf = buf;
+ char *next_buf;
+ acpi_integer control;
+
+ if (unlikely(data == NULL ||
+ data->acpi_data == NULL || data->freq_table == NULL)) {
+ return -ENODEV;
+ }
+
+ perf = data->acpi_data;
+
+
+ /* save original control values to disallow overvolting */
+ if (!original_acpi_data_control[cpu]) {
+ original_acpi_data_control[cpu] = kmalloc(sizeof(acpi_integer) *
+ perf->state_count, GFP_KERNEL);
+ if (!original_acpi_data_control[cpu]) {
+ dprintk("failed to allocate memory for old control values\n");
+ return -ENOMEM;
+ }
+ for (i = 0; i < perf->state_count; i++)
+ original_acpi_data_control[cpu][i] = perf->states[i].control;
+ }
+
+ /* set new voltages from user space */
+ for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ voltage = simple_strtoul(curr_buf, &next_buf, 10);
+ if (next_buf == curr_buf) {
+ if ((curr_buf - buf == count - 1) && (*curr_buf == '\n')) {
+ curr_buf++;
+ break;
+ }
+ dprintk("failed to parse voltage value at %i (%s)\n", i, curr_buf);
+ return -EINVAL;
+ }
+ if (voltage < 700) {
+ dprintk("skipping voltage at %i, "
+ "%u is below the minimum of 700 mV\n", i, voltage);
+ } else {
+ voltage_index = ((voltage - 700) >> 4) & INTEL_MSR_VOLTAGE;
+ j = data->freq_table[i].index;
+ original_index = original_acpi_data_control[cpu][j] &
+ INTEL_MSR_VOLTAGE;
+ if (voltage_index <= original_index) {
+ control = (original_acpi_data_control[cpu][j] &
+ INTEL_MSR_FREQUENCY) | voltage_index;
+ dprintk("setting control %x at %i, default is %x\n",
+ (unsigned int) control, i,
+ (unsigned int) original_acpi_data_control[cpu][j]);
+ perf->states[j].control = control;
+ } else {
+ dprintk("skipping voltage at %i, "
+ "%u is greater than the default %u\n",
+ i, voltage,
+ 700 + (original_index << 4));
+ }
+ }
+ curr_buf = next_buf;
+ while ((curr_buf - buf < count) && (*curr_buf == ' '))
+ curr_buf++;
+ }
+
+ /* set new voltage at current frequency */
+ data->resume = 1;
+ acpi_cpufreq_target(policy, get_cur_freq_on_cpu(cpu), CPUFREQ_RELATION_L);
+
+ return curr_buf - buf;
+}
+
+static struct freq_attr cpufreq_freq_attr_freq_voltages =
+{
+ .attr = { .name = "cpufreq_freq_voltages", .mode = 0644, .owner = THIS_MODULE },
+ .show = show_freq_voltages,
+ .store = store_freq_voltages,
+};
+
static struct freq_attr *acpi_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &cpufreq_freq_attr_freq_voltages,
NULL,
};
@@ -800,6 +916,8 @@
for_each_possible_cpu(i) {
kfree(acpi_perf_data[i]);
acpi_perf_data[i] = NULL;
+ kfree(original_acpi_data_control[i]);
+ original_acpi_data_control[i] = NULL;
}
return;
}
Would I be able to undervolt AMD Athlon 64 Mobile CPUs using this patched acpi-cpufreq driver?Whoopie wrote:Hi,
there's also https://www.dedigentoo.org/bdz/linux-ph ... re1.tar.gz which adds undervolting support to acpi-cpufreq.
Best regards,
Whoopie
It can be done. I'm doing it because otherwise my AMD would heat up too quickly. The trick is finding out (by experimenting) how low you can go with the voltage without getting an unstable system. I was able to go from 1.45V to about 1.35V with 1800MHz.pilla wrote:I mean... it can't be done. If processors could work reliably with less voltage and the same clock, then I'm sure that the manufactures would release the processors with these settings.albright wrote:that's great ... now all I need to find out (why won't somebodyAFAIK, cpufreq does both voltage and clock scaling (together)
just give me a break and *tell* me) how to control the
voltage *independently* of the clock speed (which is what
I wanted and said I wanted in the first place)
If it can't be done ... well, then it can't be done

0.4.0 - <Released date not defined yet>: Major release ¶
* Add support for the powernow-k8 driver (AMD Athlon 64 and Opteron CPUs)
Code: Select all
CUSTOM_VTABLE="1100000:828,1000000:812,900000:780,800000:748,600000:700"

Code: Select all
# Default voltages that will be restored at shutdown if SWITCH_BACK=yes
DEFAULT_VTABLE="798000:988,1064000:1116,1330000:1244,1596000:1356"
# Custom voltages that will be applied at boot time
CUSTOM_VTABLE="2000000:1164,1600000:956,1333000:876,1066000:796,800000:700"
Code: Select all
tobi linux # msrinfo
Detected 1 CPU
Vendor: 0
Family: 6
Model: 13
Mask: 8
Type: Intel Pentium M Dothan C0
CpuFreq info:
CPU 0: driver = acpi-cpufreq, governor = conservative
MSR registers:
CPU 0: PERF_CTL=0x0000000000000612, PERF_STATUS=0x06120f2906000612, FSB_FREQ=0x0000000000000311
| CPU 0 | CPU 1 |
+-------+-------+-------+-------+
| FID | VID | FID | VID |
--------+-------+-------+-------+-------+
Min | 6 | 18 | - | - |
Max | 15 | 41 | - | - |
--------+-------+-------+-------+-------+
Target | 6 | 18 | - | - |
Current | 6 | 18 | - | - |
--------+-------+-------+-------+-------+
Code: Select all
switch (perf->control_register.space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO:
dprintk("SYSTEM IO addr space\n");
data->cpu_feature = SYSTEM_IO_CAPABLE;
break;
case ACPI_ADR_SPACE_FIXED_HARDWARE:
dprintk("HARDWARE addr space\n");
if (!check_est_cpu(cpu)) {
result = -ENODEV;
goto err_unreg;
}
data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
break;
default:
dprintk("Unknown addr space %d\n",
(u32) (perf->control_register.space_id));
result = -ENODEV;
goto err_unreg;
}