diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-22 20:50:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-22 20:50:22 -0400 |
commit | 2ee8099f2c2bc74a7c2fac7f83e12a5d651681d3 (patch) | |
tree | 433ebb87a3d5d02e7df3700c846ac9af632c55f3 | |
parent | c03efdb202a4882f426ce49766859af4058c9b8a (diff) | |
parent | 24669f7d00d387799fc6a39452ab22d7f078f043 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
* master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq:
[CPUFREQ] sw_any_bug_dmi_table can be used on resume, so it isn't initdata
[CPUFREQ] Fix some more CPU hotplug locking.
[CPUFREQ] Workaround for BIOS bug in software coordination of frequency
[CPUFREQ] Longhaul - Add voltage scaling to driver
[CPUFREQ] Fix sparse warning in ondemand
[CPUFREQ] make drivers/cpufreq/cpufreq_ondemand.c:powersave_bias_target() static
[CPUFREQ] Longhaul - Add ignore_latency option
[CPUFREQ] Longhaul - Disable arbiter
[CPUFREQ][2/2] ondemand: updated add powersave_bias tunable
[CPUFREQ][1/2] ondemand: updated tune for hardware coordination
[CPUFREQ] Fix typo.
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 39 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 186 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.h | 48 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | 42 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 2 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_ondemand.c | 173 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_stats.c | 2 |
7 files changed, 391 insertions, 101 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index e6ea00edcb54..ea19d091fd41 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
33 | #include <linux/compiler.h> | 33 | #include <linux/compiler.h> |
34 | #include <linux/sched.h> /* current */ | 34 | #include <linux/sched.h> /* current */ |
35 | #include <linux/dmi.h> | ||
35 | #include <asm/io.h> | 36 | #include <asm/io.h> |
36 | #include <asm/delay.h> | 37 | #include <asm/delay.h> |
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
@@ -387,6 +388,33 @@ static int acpi_cpufreq_early_init_acpi(void) | |||
387 | return acpi_processor_preregister_performance(acpi_perf_data); | 388 | return acpi_processor_preregister_performance(acpi_perf_data); |
388 | } | 389 | } |
389 | 390 | ||
391 | /* | ||
392 | * Some BIOSes do SW_ANY coordination internally, either set it up in hw | ||
393 | * or do it in BIOS firmware and won't inform about it to OS. If not | ||
394 | * detected, this has a side effect of making CPU run at a different speed | ||
395 | * than OS intended it to run at. Detect it and handle it cleanly. | ||
396 | */ | ||
397 | static int bios_with_sw_any_bug; | ||
398 | |||
399 | static int __init sw_any_bug_found(struct dmi_system_id *d) | ||
400 | { | ||
401 | bios_with_sw_any_bug = 1; | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static struct dmi_system_id __initdata sw_any_bug_dmi_table[] = { | ||
406 | { | ||
407 | .callback = sw_any_bug_found, | ||
408 | .ident = "Supermicro Server X6DLP", | ||
409 | .matches = { | ||
410 | DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"), | ||
411 | DMI_MATCH(DMI_BIOS_VERSION, "080010"), | ||
412 | DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"), | ||
413 | }, | ||
414 | }, | ||
415 | { } | ||
416 | }; | ||
417 | |||
390 | static int | 418 | static int |
391 | acpi_cpufreq_cpu_init ( | 419 | acpi_cpufreq_cpu_init ( |
392 | struct cpufreq_policy *policy) | 420 | struct cpufreq_policy *policy) |
@@ -422,8 +450,17 @@ acpi_cpufreq_cpu_init ( | |||
422 | * coordination is required. | 450 | * coordination is required. |
423 | */ | 451 | */ |
424 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || | 452 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || |
425 | policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) | 453 | policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { |
426 | policy->cpus = perf->shared_cpu_map; | 454 | policy->cpus = perf->shared_cpu_map; |
455 | } | ||
456 | |||
457 | #ifdef CONFIG_SMP | ||
458 | dmi_check_system(sw_any_bug_dmi_table); | ||
459 | if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) { | ||
460 | policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; | ||
461 | policy->cpus = cpu_core_map[cpu]; | ||
462 | } | ||
463 | #endif | ||
427 | 464 | ||
428 | if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) { | 465 | if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) { |
429 | acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; | 466 | acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; |
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 4f2c3aeef724..f5cc9f5c9bab 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/cpufreq.h> | 29 | #include <linux/cpufreq.h> |
30 | #include <linux/pci.h> | ||
30 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
31 | #include <linux/string.h> | 32 | #include <linux/string.h> |
32 | 33 | ||
@@ -52,18 +53,26 @@ | |||
52 | #define CPU_NEHEMIAH 5 | 53 | #define CPU_NEHEMIAH 5 |
53 | 54 | ||
54 | static int cpu_model; | 55 | static int cpu_model; |
55 | static unsigned int numscales=16, numvscales; | 56 | static unsigned int numscales=16; |
56 | static unsigned int fsb; | 57 | static unsigned int fsb; |
57 | static int minvid, maxvid; | 58 | |
59 | static struct mV_pos *vrm_mV_table; | ||
60 | static unsigned char *mV_vrm_table; | ||
61 | struct f_msr { | ||
62 | unsigned char vrm; | ||
63 | }; | ||
64 | static struct f_msr f_msr_table[32]; | ||
65 | |||
66 | static unsigned int highest_speed, lowest_speed; /* kHz */ | ||
58 | static unsigned int minmult, maxmult; | 67 | static unsigned int minmult, maxmult; |
59 | static int can_scale_voltage; | 68 | static int can_scale_voltage; |
60 | static int vrmrev; | ||
61 | static struct acpi_processor *pr = NULL; | 69 | static struct acpi_processor *pr = NULL; |
62 | static struct acpi_processor_cx *cx = NULL; | 70 | static struct acpi_processor_cx *cx = NULL; |
71 | static int port22_en; | ||
63 | 72 | ||
64 | /* Module parameters */ | 73 | /* Module parameters */ |
65 | static int dont_scale_voltage; | 74 | static int scale_voltage; |
66 | 75 | static int ignore_latency; | |
67 | 76 | ||
68 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) | 77 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) |
69 | 78 | ||
@@ -71,7 +80,6 @@ static int dont_scale_voltage; | |||
71 | /* Clock ratios multiplied by 10 */ | 80 | /* Clock ratios multiplied by 10 */ |
72 | static int clock_ratio[32]; | 81 | static int clock_ratio[32]; |
73 | static int eblcr_table[32]; | 82 | static int eblcr_table[32]; |
74 | static int voltage_table[32]; | ||
75 | static unsigned int highest_speed, lowest_speed; /* kHz */ | 83 | static unsigned int highest_speed, lowest_speed; /* kHz */ |
76 | static int longhaul_version; | 84 | static int longhaul_version; |
77 | static struct cpufreq_frequency_table *longhaul_table; | 85 | static struct cpufreq_frequency_table *longhaul_table; |
@@ -124,10 +132,9 @@ static int longhaul_get_cpu_mult(void) | |||
124 | 132 | ||
125 | /* For processor with BCR2 MSR */ | 133 | /* For processor with BCR2 MSR */ |
126 | 134 | ||
127 | static void do_longhaul1(int cx_address, unsigned int clock_ratio_index) | 135 | static void do_longhaul1(unsigned int clock_ratio_index) |
128 | { | 136 | { |
129 | union msr_bcr2 bcr2; | 137 | union msr_bcr2 bcr2; |
130 | u32 t; | ||
131 | 138 | ||
132 | rdmsrl(MSR_VIA_BCR2, bcr2.val); | 139 | rdmsrl(MSR_VIA_BCR2, bcr2.val); |
133 | /* Enable software clock multiplier */ | 140 | /* Enable software clock multiplier */ |
@@ -136,13 +143,11 @@ static void do_longhaul1(int cx_address, unsigned int clock_ratio_index) | |||
136 | 143 | ||
137 | /* Sync to timer tick */ | 144 | /* Sync to timer tick */ |
138 | safe_halt(); | 145 | safe_halt(); |
139 | ACPI_FLUSH_CPU_CACHE(); | ||
140 | /* Change frequency on next halt or sleep */ | 146 | /* Change frequency on next halt or sleep */ |
141 | wrmsrl(MSR_VIA_BCR2, bcr2.val); | 147 | wrmsrl(MSR_VIA_BCR2, bcr2.val); |
142 | /* Invoke C3 */ | 148 | /* Invoke transition */ |
143 | inb(cx_address); | 149 | ACPI_FLUSH_CPU_CACHE(); |
144 | /* Dummy op - must do something useless after P_LVL3 read */ | 150 | halt(); |
145 | t = inl(acpi_fadt.xpm_tmr_blk.address); | ||
146 | 151 | ||
147 | /* Disable software clock multiplier */ | 152 | /* Disable software clock multiplier */ |
148 | local_irq_disable(); | 153 | local_irq_disable(); |
@@ -164,11 +169,16 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index) | |||
164 | longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; | 169 | longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; |
165 | longhaul.bits.EnableSoftBusRatio = 1; | 170 | longhaul.bits.EnableSoftBusRatio = 1; |
166 | 171 | ||
172 | if (can_scale_voltage) { | ||
173 | longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm; | ||
174 | longhaul.bits.EnableSoftVID = 1; | ||
175 | } | ||
176 | |||
167 | /* Sync to timer tick */ | 177 | /* Sync to timer tick */ |
168 | safe_halt(); | 178 | safe_halt(); |
169 | ACPI_FLUSH_CPU_CACHE(); | ||
170 | /* Change frequency on next halt or sleep */ | 179 | /* Change frequency on next halt or sleep */ |
171 | wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); | 180 | wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); |
181 | ACPI_FLUSH_CPU_CACHE(); | ||
172 | /* Invoke C3 */ | 182 | /* Invoke C3 */ |
173 | inb(cx_address); | 183 | inb(cx_address); |
174 | /* Dummy op - must do something useless after P_LVL3 read */ | 184 | /* Dummy op - must do something useless after P_LVL3 read */ |
@@ -227,10 +237,13 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
227 | outb(0xFF,0xA1); /* Overkill */ | 237 | outb(0xFF,0xA1); /* Overkill */ |
228 | outb(0xFE,0x21); /* TMR0 only */ | 238 | outb(0xFE,0x21); /* TMR0 only */ |
229 | 239 | ||
230 | /* Disable bus master arbitration */ | 240 | if (pr->flags.bm_control) { |
231 | if (pr->flags.bm_check) { | 241 | /* Disable bus master arbitration */ |
232 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, | 242 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, |
233 | ACPI_MTX_DO_NOT_LOCK); | 243 | ACPI_MTX_DO_NOT_LOCK); |
244 | } else if (port22_en) { | ||
245 | /* Disable AGP and PCI arbiters */ | ||
246 | outb(3, 0x22); | ||
234 | } | 247 | } |
235 | 248 | ||
236 | switch (longhaul_version) { | 249 | switch (longhaul_version) { |
@@ -244,7 +257,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
244 | */ | 257 | */ |
245 | case TYPE_LONGHAUL_V1: | 258 | case TYPE_LONGHAUL_V1: |
246 | case TYPE_LONGHAUL_V2: | 259 | case TYPE_LONGHAUL_V2: |
247 | do_longhaul1(cx->address, clock_ratio_index); | 260 | do_longhaul1(clock_ratio_index); |
248 | break; | 261 | break; |
249 | 262 | ||
250 | /* | 263 | /* |
@@ -259,14 +272,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
259 | * to work in practice. | 272 | * to work in practice. |
260 | */ | 273 | */ |
261 | case TYPE_POWERSAVER: | 274 | case TYPE_POWERSAVER: |
275 | /* Don't allow wakeup */ | ||
276 | acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, | ||
277 | ACPI_MTX_DO_NOT_LOCK); | ||
262 | do_powersaver(cx->address, clock_ratio_index); | 278 | do_powersaver(cx->address, clock_ratio_index); |
263 | break; | 279 | break; |
264 | } | 280 | } |
265 | 281 | ||
266 | /* Enable bus master arbitration */ | 282 | if (pr->flags.bm_control) { |
267 | if (pr->flags.bm_check) { | 283 | /* Enable bus master arbitration */ |
268 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, | 284 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, |
269 | ACPI_MTX_DO_NOT_LOCK); | 285 | ACPI_MTX_DO_NOT_LOCK); |
286 | } else if (port22_en) { | ||
287 | /* Enable arbiters */ | ||
288 | outb(0, 0x22); | ||
270 | } | 289 | } |
271 | 290 | ||
272 | outb(pic2_mask,0xA1); /* restore mask */ | 291 | outb(pic2_mask,0xA1); /* restore mask */ |
@@ -446,53 +465,57 @@ static int __init longhaul_get_ranges(void) | |||
446 | static void __init longhaul_setup_voltagescaling(void) | 465 | static void __init longhaul_setup_voltagescaling(void) |
447 | { | 466 | { |
448 | union msr_longhaul longhaul; | 467 | union msr_longhaul longhaul; |
468 | struct mV_pos minvid, maxvid; | ||
469 | unsigned int j, speed, pos, kHz_step, numvscales; | ||
449 | 470 | ||
450 | rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); | 471 | rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); |
451 | 472 | if (!(longhaul.bits.RevisionID & 1)) { | |
452 | if (!(longhaul.bits.RevisionID & 1)) | 473 | printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n"); |
453 | return; | 474 | return; |
475 | } | ||
476 | |||
477 | if (!longhaul.bits.VRMRev) { | ||
478 | printk (KERN_INFO PFX "VRM 8.5\n"); | ||
479 | vrm_mV_table = &vrm85_mV[0]; | ||
480 | mV_vrm_table = &mV_vrm85[0]; | ||
481 | } else { | ||
482 | printk (KERN_INFO PFX "Mobile VRM\n"); | ||
483 | vrm_mV_table = &mobilevrm_mV[0]; | ||
484 | mV_vrm_table = &mV_mobilevrm[0]; | ||
485 | } | ||
454 | 486 | ||
455 | minvid = longhaul.bits.MinimumVID; | 487 | minvid = vrm_mV_table[longhaul.bits.MinimumVID]; |
456 | maxvid = longhaul.bits.MaximumVID; | 488 | maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; |
457 | vrmrev = longhaul.bits.VRMRev; | 489 | numvscales = maxvid.pos - minvid.pos + 1; |
490 | kHz_step = (highest_speed - lowest_speed) / numvscales; | ||
458 | 491 | ||
459 | if (minvid == 0 || maxvid == 0) { | 492 | if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { |
460 | printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " | 493 | printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " |
461 | "Voltage scaling disabled.\n", | 494 | "Voltage scaling disabled.\n", |
462 | minvid/1000, minvid%1000, maxvid/1000, maxvid%1000); | 495 | minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000); |
463 | return; | 496 | return; |
464 | } | 497 | } |
465 | 498 | ||
466 | if (minvid == maxvid) { | 499 | if (minvid.mV == maxvid.mV) { |
467 | printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are " | 500 | printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are " |
468 | "both %d.%03d. Voltage scaling disabled\n", | 501 | "both %d.%03d. Voltage scaling disabled\n", |
469 | maxvid/1000, maxvid%1000); | 502 | maxvid.mV/1000, maxvid.mV%1000); |
470 | return; | 503 | return; |
471 | } | 504 | } |
472 | 505 | ||
473 | if (vrmrev==0) { | 506 | printk(KERN_INFO PFX "Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n", |
474 | dprintk ("VRM 8.5\n"); | 507 | maxvid.mV/1000, maxvid.mV%1000, |
475 | memcpy (voltage_table, vrm85scales, sizeof(voltage_table)); | 508 | minvid.mV/1000, minvid.mV%1000, |
476 | numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25; | 509 | numvscales); |
477 | } else { | 510 | |
478 | dprintk ("Mobile VRM\n"); | 511 | j = 0; |
479 | memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table)); | 512 | while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { |
480 | numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5; | 513 | speed = longhaul_table[j].frequency; |
514 | pos = (speed - lowest_speed) / kHz_step + minvid.pos; | ||
515 | f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos]; | ||
516 | j++; | ||
481 | } | 517 | } |
482 | 518 | ||
483 | /* Current voltage isn't readable at first, so we need to | ||
484 | set it to a known value. The spec says to use maxvid */ | ||
485 | longhaul.bits.RevisionKey = longhaul.bits.RevisionID; /* FIXME: This is bad. */ | ||
486 | longhaul.bits.EnableSoftVID = 1; | ||
487 | longhaul.bits.SoftVID = maxvid; | ||
488 | wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); | ||
489 | |||
490 | minvid = voltage_table[minvid]; | ||
491 | maxvid = voltage_table[maxvid]; | ||
492 | |||
493 | dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n", | ||
494 | maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales); | ||
495 | |||
496 | can_scale_voltage = 1; | 519 | can_scale_voltage = 1; |
497 | } | 520 | } |
498 | 521 | ||
@@ -540,21 +563,33 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle, | |||
540 | return 1; | 563 | return 1; |
541 | } | 564 | } |
542 | 565 | ||
566 | /* VIA don't support PM2 reg, but have something similar */ | ||
567 | static int enable_arbiter_disable(void) | ||
568 | { | ||
569 | struct pci_dev *dev; | ||
570 | u8 pci_cmd; | ||
571 | |||
572 | /* Find PLE133 host bridge */ | ||
573 | dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL); | ||
574 | if (dev != NULL) { | ||
575 | /* Enable access to port 0x22 */ | ||
576 | pci_read_config_byte(dev, 0x78, &pci_cmd); | ||
577 | if ( !(pci_cmd & 1<<7) ) { | ||
578 | pci_cmd |= 1<<7; | ||
579 | pci_write_config_byte(dev, 0x78, pci_cmd); | ||
580 | } | ||
581 | return 1; | ||
582 | } | ||
583 | return 0; | ||
584 | } | ||
585 | |||
543 | static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | 586 | static int __init longhaul_cpu_init(struct cpufreq_policy *policy) |
544 | { | 587 | { |
545 | struct cpuinfo_x86 *c = cpu_data; | 588 | struct cpuinfo_x86 *c = cpu_data; |
546 | char *cpuname=NULL; | 589 | char *cpuname=NULL; |
547 | int ret; | 590 | int ret; |
548 | 591 | ||
549 | /* Check ACPI support for C3 state */ | 592 | /* Check what we have on this motherboard */ |
550 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, | ||
551 | &longhaul_walk_callback, NULL, (void *)&pr); | ||
552 | if (pr == NULL) goto err_acpi; | ||
553 | |||
554 | cx = &pr->power.states[ACPI_STATE_C3]; | ||
555 | if (cx->address == 0 || cx->latency > 1000) goto err_acpi; | ||
556 | |||
557 | /* Now check what we have on this motherboard */ | ||
558 | switch (c->x86_model) { | 593 | switch (c->x86_model) { |
559 | case 6: | 594 | case 6: |
560 | cpu_model = CPU_SAMUEL; | 595 | cpu_model = CPU_SAMUEL; |
@@ -636,12 +671,36 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | |||
636 | break; | 671 | break; |
637 | }; | 672 | }; |
638 | 673 | ||
674 | /* Find ACPI data for processor */ | ||
675 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, | ||
676 | &longhaul_walk_callback, NULL, (void *)&pr); | ||
677 | if (pr == NULL) | ||
678 | goto err_acpi; | ||
679 | |||
680 | if (longhaul_version == TYPE_POWERSAVER) { | ||
681 | /* Check ACPI support for C3 state */ | ||
682 | cx = &pr->power.states[ACPI_STATE_C3]; | ||
683 | if (cx->address == 0 || | ||
684 | (cx->latency > 1000 && ignore_latency == 0) ) | ||
685 | goto err_acpi; | ||
686 | |||
687 | } else { | ||
688 | /* Check ACPI support for bus master arbiter disable */ | ||
689 | if (!pr->flags.bm_control) { | ||
690 | if (!enable_arbiter_disable()) { | ||
691 | printk(KERN_ERR PFX "No ACPI support. No VT8601 host bridge. Aborting.\n"); | ||
692 | return -ENODEV; | ||
693 | } else | ||
694 | port22_en = 1; | ||
695 | } | ||
696 | } | ||
697 | |||
639 | ret = longhaul_get_ranges(); | 698 | ret = longhaul_get_ranges(); |
640 | if (ret != 0) | 699 | if (ret != 0) |
641 | return ret; | 700 | return ret; |
642 | 701 | ||
643 | if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) && | 702 | if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) && |
644 | (dont_scale_voltage==0)) | 703 | (scale_voltage != 0)) |
645 | longhaul_setup_voltagescaling(); | 704 | longhaul_setup_voltagescaling(); |
646 | 705 | ||
647 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | 706 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; |
@@ -729,8 +788,10 @@ static void __exit longhaul_exit(void) | |||
729 | kfree(longhaul_table); | 788 | kfree(longhaul_table); |
730 | } | 789 | } |
731 | 790 | ||
732 | module_param (dont_scale_voltage, int, 0644); | 791 | module_param (scale_voltage, int, 0644); |
733 | MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor"); | 792 | MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); |
793 | module_param(ignore_latency, int, 0644); | ||
794 | MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test"); | ||
734 | 795 | ||
735 | MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); | 796 | MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); |
736 | MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); | 797 | MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); |
@@ -738,4 +799,3 @@ MODULE_LICENSE ("GPL"); | |||
738 | 799 | ||
739 | late_initcall(longhaul_init); | 800 | late_initcall(longhaul_init); |
740 | module_exit(longhaul_exit); | 801 | module_exit(longhaul_exit); |
741 | |||
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.h b/arch/i386/kernel/cpu/cpufreq/longhaul.h index d3a95d77ee85..bc4682aad69b 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.h +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.h | |||
@@ -450,17 +450,45 @@ static int __initdata nehemiah_c_eblcr[32] = { | |||
450 | * Voltage scales. Div/Mod by 1000 to get actual voltage. | 450 | * Voltage scales. Div/Mod by 1000 to get actual voltage. |
451 | * Which scale to use depends on the VRM type in use. | 451 | * Which scale to use depends on the VRM type in use. |
452 | */ | 452 | */ |
453 | static int __initdata vrm85scales[32] = { | 453 | |
454 | 1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700, | 454 | struct mV_pos { |
455 | 1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300, | 455 | unsigned short mV; |
456 | 1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725, | 456 | unsigned short pos; |
457 | 1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325, | 457 | }; |
458 | |||
459 | static struct mV_pos __initdata vrm85_mV[32] = { | ||
460 | {1250, 8}, {1200, 6}, {1150, 4}, {1100, 2}, | ||
461 | {1050, 0}, {1800, 30}, {1750, 28}, {1700, 26}, | ||
462 | {1650, 24}, {1600, 22}, {1550, 20}, {1500, 18}, | ||
463 | {1450, 16}, {1400, 14}, {1350, 12}, {1300, 10}, | ||
464 | {1275, 9}, {1225, 7}, {1175, 5}, {1125, 3}, | ||
465 | {1075, 1}, {1825, 31}, {1775, 29}, {1725, 27}, | ||
466 | {1675, 25}, {1625, 23}, {1575, 21}, {1525, 19}, | ||
467 | {1475, 17}, {1425, 15}, {1375, 13}, {1325, 11} | ||
468 | }; | ||
469 | |||
470 | static unsigned char __initdata mV_vrm85[32] = { | ||
471 | 0x04, 0x14, 0x03, 0x13, 0x02, 0x12, 0x01, 0x11, | ||
472 | 0x00, 0x10, 0x0f, 0x1f, 0x0e, 0x1e, 0x0d, 0x1d, | ||
473 | 0x0c, 0x1c, 0x0b, 0x1b, 0x0a, 0x1a, 0x09, 0x19, | ||
474 | 0x08, 0x18, 0x07, 0x17, 0x06, 0x16, 0x05, 0x15 | ||
475 | }; | ||
476 | |||
477 | static struct mV_pos __initdata mobilevrm_mV[32] = { | ||
478 | {1750, 31}, {1700, 30}, {1650, 29}, {1600, 28}, | ||
479 | {1550, 27}, {1500, 26}, {1450, 25}, {1400, 24}, | ||
480 | {1350, 23}, {1300, 22}, {1250, 21}, {1200, 20}, | ||
481 | {1150, 19}, {1100, 18}, {1050, 17}, {1000, 16}, | ||
482 | {975, 15}, {950, 14}, {925, 13}, {900, 12}, | ||
483 | {875, 11}, {850, 10}, {825, 9}, {800, 8}, | ||
484 | {775, 7}, {750, 6}, {725, 5}, {700, 4}, | ||
485 | {675, 3}, {650, 2}, {625, 1}, {600, 0} | ||
458 | }; | 486 | }; |
459 | 487 | ||
460 | static int __initdata mobilevrmscales[32] = { | 488 | static unsigned char __initdata mV_mobilevrm[32] = { |
461 | 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, | 489 | 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, |
462 | 1600, 1550, 1500, 1450, 1500, 1350, 1300, -1, | 490 | 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, |
463 | 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, | 491 | 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, |
464 | 1075, 1050, 1025, 1000, 975, 950, 925, -1, | 492 | 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 |
465 | }; | 493 | }; |
466 | 494 | ||
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index b77f1358bd79..7a9325349e94 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | |||
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI | 24 | #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI |
25 | #include <linux/acpi.h> | 25 | #include <linux/acpi.h> |
26 | #include <linux/dmi.h> | ||
26 | #include <acpi/processor.h> | 27 | #include <acpi/processor.h> |
27 | #endif | 28 | #endif |
28 | 29 | ||
@@ -377,6 +378,35 @@ static int centrino_cpu_early_init_acpi(void) | |||
377 | return 0; | 378 | return 0; |
378 | } | 379 | } |
379 | 380 | ||
381 | |||
382 | /* | ||
383 | * Some BIOSes do SW_ANY coordination internally, either set it up in hw | ||
384 | * or do it in BIOS firmware and won't inform about it to OS. If not | ||
385 | * detected, this has a side effect of making CPU run at a different speed | ||
386 | * than OS intended it to run at. Detect it and handle it cleanly. | ||
387 | */ | ||
388 | static int bios_with_sw_any_bug; | ||
389 | static int __init sw_any_bug_found(struct dmi_system_id *d) | ||
390 | { | ||
391 | bios_with_sw_any_bug = 1; | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | |||
396 | static struct dmi_system_id sw_any_bug_dmi_table[] = { | ||
397 | { | ||
398 | .callback = sw_any_bug_found, | ||
399 | .ident = "Supermicro Server X6DLP", | ||
400 | .matches = { | ||
401 | DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"), | ||
402 | DMI_MATCH(DMI_BIOS_VERSION, "080010"), | ||
403 | DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"), | ||
404 | }, | ||
405 | }, | ||
406 | { } | ||
407 | }; | ||
408 | |||
409 | |||
380 | /* | 410 | /* |
381 | * centrino_cpu_init_acpi - register with ACPI P-States library | 411 | * centrino_cpu_init_acpi - register with ACPI P-States library |
382 | * | 412 | * |
@@ -398,14 +428,24 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) | |||
398 | dprintk(PFX "obtaining ACPI data failed\n"); | 428 | dprintk(PFX "obtaining ACPI data failed\n"); |
399 | return -EIO; | 429 | return -EIO; |
400 | } | 430 | } |
431 | |||
401 | policy->shared_type = p->shared_type; | 432 | policy->shared_type = p->shared_type; |
402 | /* | 433 | /* |
403 | * Will let policy->cpus know about dependency only when software | 434 | * Will let policy->cpus know about dependency only when software |
404 | * coordination is required. | 435 | * coordination is required. |
405 | */ | 436 | */ |
406 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || | 437 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || |
407 | policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) | 438 | policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { |
408 | policy->cpus = p->shared_cpu_map; | 439 | policy->cpus = p->shared_cpu_map; |
440 | } | ||
441 | |||
442 | #ifdef CONFIG_SMP | ||
443 | dmi_check_system(sw_any_bug_dmi_table); | ||
444 | if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) { | ||
445 | policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; | ||
446 | policy->cpus = cpu_core_map[cpu]; | ||
447 | } | ||
448 | #endif | ||
409 | 449 | ||
410 | /* verify the acpi_data */ | 450 | /* verify the acpi_data */ |
411 | if (p->state_count <= 1) { | 451 | if (p->state_count <= 1) { |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b3df613ae4ec..d35a9f06ab7b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg) | 32 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg) |
33 | 33 | ||
34 | /** | 34 | /** |
35 | * The "cpufreq driver" - the arch- or hardware-dependend low | 35 | * The "cpufreq driver" - the arch- or hardware-dependent low |
36 | * level driver of CPUFreq support, and its spinlock. This lock | 36 | * level driver of CPUFreq support, and its spinlock. This lock |
37 | * also protects the cpufreq_cpu_data array. | 37 | * also protects the cpufreq_cpu_data array. |
38 | */ | 38 | */ |
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 52cf1f021825..bf8aa45d4f01 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c | |||
@@ -55,6 +55,10 @@ struct cpu_dbs_info_s { | |||
55 | struct cpufreq_policy *cur_policy; | 55 | struct cpufreq_policy *cur_policy; |
56 | struct work_struct work; | 56 | struct work_struct work; |
57 | unsigned int enable; | 57 | unsigned int enable; |
58 | struct cpufreq_frequency_table *freq_table; | ||
59 | unsigned int freq_lo; | ||
60 | unsigned int freq_lo_jiffies; | ||
61 | unsigned int freq_hi_jiffies; | ||
58 | }; | 62 | }; |
59 | static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); | 63 | static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); |
60 | 64 | ||
@@ -72,15 +76,15 @@ static DEFINE_MUTEX(dbs_mutex); | |||
72 | 76 | ||
73 | static struct workqueue_struct *kondemand_wq; | 77 | static struct workqueue_struct *kondemand_wq; |
74 | 78 | ||
75 | struct dbs_tuners { | 79 | static struct dbs_tuners { |
76 | unsigned int sampling_rate; | 80 | unsigned int sampling_rate; |
77 | unsigned int up_threshold; | 81 | unsigned int up_threshold; |
78 | unsigned int ignore_nice; | 82 | unsigned int ignore_nice; |
79 | }; | 83 | unsigned int powersave_bias; |
80 | 84 | } dbs_tuners_ins = { | |
81 | static struct dbs_tuners dbs_tuners_ins = { | ||
82 | .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, | 85 | .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, |
83 | .ignore_nice = 0, | 86 | .ignore_nice = 0, |
87 | .powersave_bias = 0, | ||
84 | }; | 88 | }; |
85 | 89 | ||
86 | static inline cputime64_t get_cpu_idle_time(unsigned int cpu) | 90 | static inline cputime64_t get_cpu_idle_time(unsigned int cpu) |
@@ -96,6 +100,70 @@ static inline cputime64_t get_cpu_idle_time(unsigned int cpu) | |||
96 | return retval; | 100 | return retval; |
97 | } | 101 | } |
98 | 102 | ||
103 | /* | ||
104 | * Find right freq to be set now with powersave_bias on. | ||
105 | * Returns the freq_hi to be used right now and will set freq_hi_jiffies, | ||
106 | * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs. | ||
107 | */ | ||
108 | static unsigned int powersave_bias_target(struct cpufreq_policy *policy, | ||
109 | unsigned int freq_next, | ||
110 | unsigned int relation) | ||
111 | { | ||
112 | unsigned int freq_req, freq_reduc, freq_avg; | ||
113 | unsigned int freq_hi, freq_lo; | ||
114 | unsigned int index = 0; | ||
115 | unsigned int jiffies_total, jiffies_hi, jiffies_lo; | ||
116 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, policy->cpu); | ||
117 | |||
118 | if (!dbs_info->freq_table) { | ||
119 | dbs_info->freq_lo = 0; | ||
120 | dbs_info->freq_lo_jiffies = 0; | ||
121 | return freq_next; | ||
122 | } | ||
123 | |||
124 | cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next, | ||
125 | relation, &index); | ||
126 | freq_req = dbs_info->freq_table[index].frequency; | ||
127 | freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000; | ||
128 | freq_avg = freq_req - freq_reduc; | ||
129 | |||
130 | /* Find freq bounds for freq_avg in freq_table */ | ||
131 | index = 0; | ||
132 | cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, | ||
133 | CPUFREQ_RELATION_H, &index); | ||
134 | freq_lo = dbs_info->freq_table[index].frequency; | ||
135 | index = 0; | ||
136 | cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, | ||
137 | CPUFREQ_RELATION_L, &index); | ||
138 | freq_hi = dbs_info->freq_table[index].frequency; | ||
139 | |||
140 | /* Find out how long we have to be in hi and lo freqs */ | ||
141 | if (freq_hi == freq_lo) { | ||
142 | dbs_info->freq_lo = 0; | ||
143 | dbs_info->freq_lo_jiffies = 0; | ||
144 | return freq_lo; | ||
145 | } | ||
146 | jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); | ||
147 | jiffies_hi = (freq_avg - freq_lo) * jiffies_total; | ||
148 | jiffies_hi += ((freq_hi - freq_lo) / 2); | ||
149 | jiffies_hi /= (freq_hi - freq_lo); | ||
150 | jiffies_lo = jiffies_total - jiffies_hi; | ||
151 | dbs_info->freq_lo = freq_lo; | ||
152 | dbs_info->freq_lo_jiffies = jiffies_lo; | ||
153 | dbs_info->freq_hi_jiffies = jiffies_hi; | ||
154 | return freq_hi; | ||
155 | } | ||
156 | |||
157 | static void ondemand_powersave_bias_init(void) | ||
158 | { | ||
159 | int i; | ||
160 | for_each_online_cpu(i) { | ||
161 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, i); | ||
162 | dbs_info->freq_table = cpufreq_frequency_get_table(i); | ||
163 | dbs_info->freq_lo = 0; | ||
164 | } | ||
165 | } | ||
166 | |||
99 | /************************** sysfs interface ************************/ | 167 | /************************** sysfs interface ************************/ |
100 | static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) | 168 | static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) |
101 | { | 169 | { |
@@ -124,6 +192,7 @@ static ssize_t show_##file_name \ | |||
124 | show_one(sampling_rate, sampling_rate); | 192 | show_one(sampling_rate, sampling_rate); |
125 | show_one(up_threshold, up_threshold); | 193 | show_one(up_threshold, up_threshold); |
126 | show_one(ignore_nice_load, ignore_nice); | 194 | show_one(ignore_nice_load, ignore_nice); |
195 | show_one(powersave_bias, powersave_bias); | ||
127 | 196 | ||
128 | static ssize_t store_sampling_rate(struct cpufreq_policy *unused, | 197 | static ssize_t store_sampling_rate(struct cpufreq_policy *unused, |
129 | const char *buf, size_t count) | 198 | const char *buf, size_t count) |
@@ -198,6 +267,27 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy, | |||
198 | return count; | 267 | return count; |
199 | } | 268 | } |
200 | 269 | ||
270 | static ssize_t store_powersave_bias(struct cpufreq_policy *unused, | ||
271 | const char *buf, size_t count) | ||
272 | { | ||
273 | unsigned int input; | ||
274 | int ret; | ||
275 | ret = sscanf(buf, "%u", &input); | ||
276 | |||
277 | if (ret != 1) | ||
278 | return -EINVAL; | ||
279 | |||
280 | if (input > 1000) | ||
281 | input = 1000; | ||
282 | |||
283 | mutex_lock(&dbs_mutex); | ||
284 | dbs_tuners_ins.powersave_bias = input; | ||
285 | ondemand_powersave_bias_init(); | ||
286 | mutex_unlock(&dbs_mutex); | ||
287 | |||
288 | return count; | ||
289 | } | ||
290 | |||
201 | #define define_one_rw(_name) \ | 291 | #define define_one_rw(_name) \ |
202 | static struct freq_attr _name = \ | 292 | static struct freq_attr _name = \ |
203 | __ATTR(_name, 0644, show_##_name, store_##_name) | 293 | __ATTR(_name, 0644, show_##_name, store_##_name) |
@@ -205,6 +295,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name) | |||
205 | define_one_rw(sampling_rate); | 295 | define_one_rw(sampling_rate); |
206 | define_one_rw(up_threshold); | 296 | define_one_rw(up_threshold); |
207 | define_one_rw(ignore_nice_load); | 297 | define_one_rw(ignore_nice_load); |
298 | define_one_rw(powersave_bias); | ||
208 | 299 | ||
209 | static struct attribute * dbs_attributes[] = { | 300 | static struct attribute * dbs_attributes[] = { |
210 | &sampling_rate_max.attr, | 301 | &sampling_rate_max.attr, |
@@ -212,6 +303,7 @@ static struct attribute * dbs_attributes[] = { | |||
212 | &sampling_rate.attr, | 303 | &sampling_rate.attr, |
213 | &up_threshold.attr, | 304 | &up_threshold.attr, |
214 | &ignore_nice_load.attr, | 305 | &ignore_nice_load.attr, |
306 | &powersave_bias.attr, | ||
215 | NULL | 307 | NULL |
216 | }; | 308 | }; |
217 | 309 | ||
@@ -234,6 +326,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) | |||
234 | if (!this_dbs_info->enable) | 326 | if (!this_dbs_info->enable) |
235 | return; | 327 | return; |
236 | 328 | ||
329 | this_dbs_info->freq_lo = 0; | ||
237 | policy = this_dbs_info->cur_policy; | 330 | policy = this_dbs_info->cur_policy; |
238 | cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); | 331 | cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); |
239 | total_ticks = (unsigned int) cputime64_sub(cur_jiffies, | 332 | total_ticks = (unsigned int) cputime64_sub(cur_jiffies, |
@@ -274,11 +367,18 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) | |||
274 | /* Check for frequency increase */ | 367 | /* Check for frequency increase */ |
275 | if (load > dbs_tuners_ins.up_threshold) { | 368 | if (load > dbs_tuners_ins.up_threshold) { |
276 | /* if we are already at full speed then break out early */ | 369 | /* if we are already at full speed then break out early */ |
277 | if (policy->cur == policy->max) | 370 | if (!dbs_tuners_ins.powersave_bias) { |
278 | return; | 371 | if (policy->cur == policy->max) |
279 | 372 | return; | |
280 | __cpufreq_driver_target(policy, policy->max, | 373 | |
281 | CPUFREQ_RELATION_H); | 374 | __cpufreq_driver_target(policy, policy->max, |
375 | CPUFREQ_RELATION_H); | ||
376 | } else { | ||
377 | int freq = powersave_bias_target(policy, policy->max, | ||
378 | CPUFREQ_RELATION_H); | ||
379 | __cpufreq_driver_target(policy, freq, | ||
380 | CPUFREQ_RELATION_L); | ||
381 | } | ||
282 | return; | 382 | return; |
283 | } | 383 | } |
284 | 384 | ||
@@ -293,37 +393,64 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) | |||
293 | * policy. To be safe, we focus 10 points under the threshold. | 393 | * policy. To be safe, we focus 10 points under the threshold. |
294 | */ | 394 | */ |
295 | if (load < (dbs_tuners_ins.up_threshold - 10)) { | 395 | if (load < (dbs_tuners_ins.up_threshold - 10)) { |
296 | unsigned int freq_next; | 396 | unsigned int freq_next = (policy->cur * load) / |
297 | freq_next = (policy->cur * load) / | ||
298 | (dbs_tuners_ins.up_threshold - 10); | 397 | (dbs_tuners_ins.up_threshold - 10); |
299 | 398 | if (!dbs_tuners_ins.powersave_bias) { | |
300 | __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); | 399 | __cpufreq_driver_target(policy, freq_next, |
400 | CPUFREQ_RELATION_L); | ||
401 | } else { | ||
402 | int freq = powersave_bias_target(policy, freq_next, | ||
403 | CPUFREQ_RELATION_L); | ||
404 | __cpufreq_driver_target(policy, freq, | ||
405 | CPUFREQ_RELATION_L); | ||
406 | } | ||
301 | } | 407 | } |
302 | } | 408 | } |
303 | 409 | ||
410 | /* Sampling types */ | ||
411 | enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; | ||
412 | |||
304 | static void do_dbs_timer(void *data) | 413 | static void do_dbs_timer(void *data) |
305 | { | 414 | { |
306 | unsigned int cpu = smp_processor_id(); | 415 | unsigned int cpu = smp_processor_id(); |
307 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); | 416 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); |
417 | /* We want all CPUs to do sampling nearly on same jiffy */ | ||
418 | int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); | ||
419 | delay -= jiffies % delay; | ||
308 | 420 | ||
309 | if (!dbs_info->enable) | 421 | if (!dbs_info->enable) |
310 | return; | 422 | return; |
311 | 423 | /* Common NORMAL_SAMPLE setup */ | |
312 | lock_cpu_hotplug(); | 424 | INIT_WORK(&dbs_info->work, do_dbs_timer, (void *)DBS_NORMAL_SAMPLE); |
313 | dbs_check_cpu(dbs_info); | 425 | if (!dbs_tuners_ins.powersave_bias || |
314 | unlock_cpu_hotplug(); | 426 | (unsigned long) data == DBS_NORMAL_SAMPLE) { |
315 | queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, | 427 | lock_cpu_hotplug(); |
316 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); | 428 | dbs_check_cpu(dbs_info); |
429 | unlock_cpu_hotplug(); | ||
430 | if (dbs_info->freq_lo) { | ||
431 | /* Setup timer for SUB_SAMPLE */ | ||
432 | INIT_WORK(&dbs_info->work, do_dbs_timer, | ||
433 | (void *)DBS_SUB_SAMPLE); | ||
434 | delay = dbs_info->freq_hi_jiffies; | ||
435 | } | ||
436 | } else { | ||
437 | __cpufreq_driver_target(dbs_info->cur_policy, | ||
438 | dbs_info->freq_lo, | ||
439 | CPUFREQ_RELATION_H); | ||
440 | } | ||
441 | queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); | ||
317 | } | 442 | } |
318 | 443 | ||
319 | static inline void dbs_timer_init(unsigned int cpu) | 444 | static inline void dbs_timer_init(unsigned int cpu) |
320 | { | 445 | { |
321 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); | 446 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); |
447 | /* We want all CPUs to do sampling nearly on same jiffy */ | ||
448 | int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); | ||
449 | delay -= jiffies % delay; | ||
322 | 450 | ||
323 | INIT_WORK(&dbs_info->work, do_dbs_timer, 0); | 451 | ondemand_powersave_bias_init(); |
324 | queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, | 452 | INIT_WORK(&dbs_info->work, do_dbs_timer, NULL); |
325 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); | 453 | queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); |
326 | return; | ||
327 | } | 454 | } |
328 | 455 | ||
329 | static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) | 456 | static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) |
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 25eee5394201..c2ecc599dc5f 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c | |||
@@ -350,12 +350,10 @@ __init cpufreq_stats_init(void) | |||
350 | } | 350 | } |
351 | 351 | ||
352 | register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); | 352 | register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); |
353 | lock_cpu_hotplug(); | ||
354 | for_each_online_cpu(cpu) { | 353 | for_each_online_cpu(cpu) { |
355 | cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE, | 354 | cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE, |
356 | (void *)(long)cpu); | 355 | (void *)(long)cpu); |
357 | } | 356 | } |
358 | unlock_cpu_hotplug(); | ||
359 | return 0; | 357 | return 0; |
360 | } | 358 | } |
361 | static void | 359 | static void |