bk://linux-dj.bkbits.net/cpufreq
davej@redhat.com|ChangeSet|20040724013326|17788 davej

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/07/23 21:33:26-04:00 davej@redhat.com 
#   [CPUFREQ] disable interrupts around transitions in longhaul.
#   Re-reading the spec revealed this omission.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/longhaul.c
#   2004/07/23 21:32:46-04:00 davej@redhat.com +8 -0
#   [CPUFREQ] disable interrupts around transitions in longhaul.
#   Re-reading the spec revealed this omission.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/23 20:02:20-04:00 davej@redhat.com 
#   [CPUFREQ] abstract out powersaver code in longhaul driver.
#   99% of these two implementations are the same, so abstract it out into a
#   seperate function.  Also add another bunch of comments.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
#   
# 
# arch/i386/kernel/cpu/cpufreq/longhaul.c
#   2004/07/23 20:01:50-04:00 davej@redhat.com +31 -32
#   [CPUFREQ] abstract out powersaver code in longhaul driver.
#   99% of these two implementations are the same, so abstract it out into a
#   seperate function.  Also add another bunch of comments.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
#   
# 
# ChangeSet
#   2004/07/23 19:31:03-04:00 davej@redhat.com 
#   [CPUFREQ] Fix up some comments in longhaul.
#   Some of this stuff is very wrong, time to sit down with datasheets
#   and fix up some of this mess. The problem is this driver pulls info
#   from multiple datasheets, and some of them conflict.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/longhaul.c
#   2004/07/23 19:30:22-04:00 davej@redhat.com +18 -7
#   [CPUFREQ] Fix up some comments in longhaul.
#   Some of this stuff is very wrong, time to sit down with datasheets
#   and fix up some of this mess. The problem is this driver pulls info
#   from multiple datasheets, and some of them conflict.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/13 12:33:44-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
#   2004/07/13 12:33:40-07:00 akpm@bix.(none) +0 -1
#   Auto merged
# 
# ChangeSet
#   2004/07/12 21:02:29-07:00 akpm@bix.(none) 
#   Merge bk://linux-dj.bkbits.net/cpufreq
#   into bix.(none):/usr/src/bk-cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/12 21:02:25-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/13 00:18:00+01:00 davej@redhat.com 
#   [CPUFREQ] powernowk8_cpu_exit may not be __exit but can be __devexit.
#   Thanks to Arjan for noticing this bug.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/07/13 00:17:52+01:00 davej@redhat.com +2 -2
#   [CPUFREQ] powernowk8_cpu_exit may not be __exit but can be __devexit.
#   Thanks to Arjan for noticing this bug.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/13 00:15:08+01:00 davej@redhat.com 
#   [CPUFREQ] fix CONFIG_ACPI_PROCESSOR="m", CONFIG_X86_POWERNOW_K{7,8}="y" build issue
#   Fix the build dependency between powernow-k{7,8} and acpi/processor.o by
#   adding a CONFIG_X86_POWERNOW_K{7,8}_ACPI bool, just like SPEEDSTEP_CENTRINO
#   does it. See http://forums.gentoo.org/viewtopic.php?t=186887 for a
#   bugreport.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/x86_64/kernel/cpufreq/Kconfig
#   2004/07/13 00:14:59+01:00 davej@redhat.com +5 -0
#   [CPUFREQ] fix CONFIG_ACPI_PROCESSOR="m", CONFIG_X86_POWERNOW_K{7,8}="y" build issue
#   Fix the build dependency between powernow-k{7,8} and acpi/processor.o by
#   adding a CONFIG_X86_POWERNOW_K{7,8}_ACPI bool, just like SPEEDSTEP_CENTRINO
#   does it. See http://forums.gentoo.org/viewtopic.php?t=186887 for a
#   bugreport.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/07/13 00:14:59+01:00 davej@redhat.com +2 -2
#   [CPUFREQ] fix CONFIG_ACPI_PROCESSOR="m", CONFIG_X86_POWERNOW_K{7,8}="y" build issue
#   Fix the build dependency between powernow-k{7,8} and acpi/processor.o by
#   adding a CONFIG_X86_POWERNOW_K{7,8}_ACPI bool, just like SPEEDSTEP_CENTRINO
#   does it. See http://forums.gentoo.org/viewtopic.php?t=186887 for a
#   bugreport.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/13 00:14:59+01:00 davej@redhat.com +5 -5
#   [CPUFREQ] fix CONFIG_ACPI_PROCESSOR="m", CONFIG_X86_POWERNOW_K{7,8}="y" build issue
#   Fix the build dependency between powernow-k{7,8} and acpi/processor.o by
#   adding a CONFIG_X86_POWERNOW_K{7,8}_ACPI bool, just like SPEEDSTEP_CENTRINO
#   does it. See http://forums.gentoo.org/viewtopic.php?t=186887 for a
#   bugreport.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/Kconfig
#   2004/07/13 00:14:59+01:00 davej@redhat.com +10 -0
#   [CPUFREQ] fix CONFIG_ACPI_PROCESSOR="m", CONFIG_X86_POWERNOW_K{7,8}="y" build issue
#   Fix the build dependency between powernow-k{7,8} and acpi/processor.o by
#   adding a CONFIG_X86_POWERNOW_K{7,8}_ACPI bool, just like SPEEDSTEP_CENTRINO
#   does it. See http://forums.gentoo.org/viewtopic.php?t=186887 for a
#   bugreport.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/11 11:55:46+01:00 davej@redhat.com 
#   [CPUFREQ] reorder cpufreq.c for inlining
#   
#   Trying to compile drivers/cpufreq/cpufreq.c with gcc 3.4 and
#     # define inline         __inline__ __attribute__((always_inline))
#   results in the following compile error:
#     CC      drivers/cpufreq/cpufreq.o
#   drivers/cpufreq/cpufreq.c: In function `cpufreq_resume':
#   drivers/cpufreq/cpufreq.c:39: sorry, unimplemented: inlining failed in
#   call to 'adjust_jiffies': function body not available
#   drivers/cpufreq/cpufreq.c:628: sorry, unimplemented: called from here
#   make[2]: *** [drivers/cpufreq/cpufreq.o] Error 1
#   
#   Signed-off-by: Adrian Bunk <bunk@fs.tum.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# drivers/cpufreq/cpufreq.c
#   2004/07/11 11:55:38+01:00 davej@redhat.com +80 -80
#   [CPUFREQ] reorder cpufreq.c for inlining
#   
#   Trying to compile drivers/cpufreq/cpufreq.c with gcc 3.4 and
#     # define inline         __inline__ __attribute__((always_inline))
#   results in the following compile error:
#     CC      drivers/cpufreq/cpufreq.o
#   drivers/cpufreq/cpufreq.c: In function `cpufreq_resume':
#   drivers/cpufreq/cpufreq.c:39: sorry, unimplemented: inlining failed in
#   call to 'adjust_jiffies': function body not available
#   drivers/cpufreq/cpufreq.c:628: sorry, unimplemented: called from here
#   make[2]: *** [drivers/cpufreq/cpufreq.o] Error 1
#   
#   Signed-off-by: Adrian Bunk <bunk@fs.tum.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/08 14:19:23-07:00 akpm@bix.(none) 
#   Merge bk://linux-dj.bkbits.net/cpufreq
#   into bix.(none):/usr/src/bk-cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/08 14:19:19-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/08 14:08:47+01:00 davej@redhat.com 
#   [CPUFREQ] fix whitespace after merge.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/08 14:07:31+01:00 davej@redhat.com +1 -1
#   [CPUFREQ] fix whitespace after merge.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/08 13:59:21+01:00 davej@delerium.codemonkey.org.uk 
#   Merge delerium.codemonkey.org.uk:/mnt/data/src/bk/bk-linus
#   into delerium.codemonkey.org.uk:/mnt/data/src/bk/cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/08 13:59:14+01:00 davej@delerium.codemonkey.org.uk +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/04 22:43:06-07:00 akpm@bix.(none) 
#   Merge bk://linux-dj.bkbits.net/cpufreq
#   into bix.(none):/usr/src/bk-cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/04 22:43:03-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/05 01:36:09+01:00 davej@redhat.com 
#   [CPUFREQ] Remove out of date comment from powernow-k7
#   This has had significant amount of testing since it got merged, and
#   nothing nasty has actually ever happened.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/05 01:36:00+01:00 davej@redhat.com +0 -2
#   [CPUFREQ] Remove out of date comment from powernow-k7
#   This has had significant amount of testing since it got merged, and
#   nothing nasty has actually ever happened.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/05 01:34:47+01:00 davej@redhat.com 
#   [CPUFREQ] REmove more trailing whitespace
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/05 01:34:40+01:00 davej@redhat.com +9 -9
#   [CPUFREQ] REmove more trailing whitespace
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/05 01:20:53+01:00 davej@redhat.com 
#   [CPUFREQ] Make powernow-k7 debug printk a runtime option.
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/05 01:20:44+01:00 davej@redhat.com +19 -9
#   [CPUFREQ] Make powernow-k7 debug printk a runtime option.
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/04 01:18:17+01:00 davej@redhat.com 
#   [CPUFREQ] fix userspace resume support.
#   
#   Fix resume support in the userspace cpufreq governor: we need to set the
#   CPU to the frequency last echo'ed by userspace into this governor's files.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# drivers/cpufreq/cpufreq_userspace.c
#   2004/07/04 01:18:10+01:00 davej@redhat.com +10 -0
#   [CPUFREQ] fix userspace resume support.
#   
#   Fix resume support in the userspace cpufreq governor: we need to set the
#   CPU to the frequency last echo'ed by userspace into this governor's files.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/04 01:16:06+01:00 davej@redhat.com 
#   [CPUFREQ] fix double "out-of-sync" warning on resume.
#   
#   - Rephrase "out-of-sync" warning (partly) based upon Gerald Britton's suggestion
#   - Also update cpufreq's opinion of current cpu frequency upon resume, else the
#     "out-of-sync" warning will appear twice. Thanks to Gerald Britton for noting this.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# drivers/cpufreq/cpufreq.c
#   2004/07/04 01:15:58+01:00 davej@redhat.com +6 -5
#   [CPUFREQ] fix double "out-of-sync" warning on resume.
#   
#   - Rephrase "out-of-sync" warning (partly) based upon Gerald Britton's suggestion
#   - Also update cpufreq's opinion of current cpu frequency upon resume, else the
#     "out-of-sync" warning will appear twice. Thanks to Gerald Britton for noting this.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/03 18:05:50+01:00 davej@redhat.com 
#   [CPUFREQ] Fix FSB calculation in powernow-k7
#   
#   use the maximum fid instead of the current fid.
#   
#   From: Bruno Ducrot
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/07/03 18:05:42+01:00 davej@redhat.com +1 -1
#   [CPUFREQ] Fix FSB calculation in powernow-k7
#   
#   use the maximum fid instead of the current fid.
#   
#   From: Bruno Ducrot
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/07/03 17:17:16+01:00 davej@redhat.com 
#   [CPUFREQ] Trailing whitespace removal in longrun driver.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/longrun.c
#   2004/07/03 17:17:09+01:00 davej@redhat.com +21 -21
#   [CPUFREQ] Trailing whitespace removal in longrun driver.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/06/29 23:43:48+01:00 davej@redhat.com 
#   [CPUFREQ] Fix sparse NULL ptr warning.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
#   2004/06/29 23:43:41+01:00 davej@redhat.com +1 -1
#   [CPUFREQ] Fix sparse NULL ptr warning.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/06/27 16:53:42-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/06/27 16:53:38-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/20 00:04:48+01:00 davej@redhat.com 
#   [CPUFREQ] Stop powernow-k7 printk'ing tab characters.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/06/20 00:04:29+01:00 davej@redhat.com +5 -5
#   [CPUFREQ] Stop powernow-k7 printk'ing tab characters.
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# ChangeSet
#   2004/06/16 17:58:22+01:00 davej@redhat.com 
#   [CPUFREQ] new Dothan variant for speedstep-centrino
#   
#   Add support for new Dothan variant (CPUID 0x6d6) to speedstep-centrino.
#   Noted to be missing and tested by Athul Acharya.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
#   2004/06/16 17:58:14+01:00 davej@redhat.com +9 -1
#   [CPUFREQ] new Dothan variant for speedstep-centrino
#   
#   Add support for new Dothan variant (CPUID 0x6d6) to speedstep-centrino.
#   Noted to be missing and tested by Athul Acharya.
#   
#   Signed-off-by: Dominik Brodowski <linux@brodo.de>
#   Signed-off-by: Dave Jones <davej@redhat.com>
# 
diff -Nru a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig
--- a/arch/i386/kernel/cpu/cpufreq/Kconfig	2004-08-01 22:17:03 -07:00
+++ b/arch/i386/kernel/cpu/cpufreq/Kconfig	2004-08-01 22:17:03 -07:00
@@ -88,6 +88,11 @@
 
 	  If in doubt, say N.
 
+config X86_POWERNOW_K7_ACPI
+	bool
+	depends on ((X86_POWERNOW_K7 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K7 = "y" && ACPI_PROCESSOR = "y"))
+	default y
+
 config X86_POWERNOW_K8
 	tristate "AMD Opteron/Athlon64 PowerNow!"
 	depends on CPU_FREQ && EXPERIMENTAL
@@ -97,6 +102,11 @@
 	  For details, take a look at <file:Documentation/cpu-freq/>.
 
 	  If in doubt, say N.
+
+config X86_POWERNOW_K8_ACPI
+	bool
+	depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
+	default y
 
 config X86_GX_SUSPMOD
 	tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
diff -Nru a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c	2004-08-01 22:17:03 -07:00
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c	2004-08-01 22:17:03 -07:00
@@ -5,14 +5,19 @@
  *  Licensed under the terms of the GNU GPL License version 2.
  *  Based upon datasheets & sample CPUs kindly provided by VIA.
  *
- *  VIA have currently 2 different versions of Longhaul.
+ *  VIA have currently 3 different versions of Longhaul.
  *  Version 1 (Longhaul) uses the BCR2 MSR at 0x1147.
- *   It is present only in Samuel 1, Samuel 2 and Ezra.
- *  Version 2 (Powersaver) uses the POWERSAVER MSR at 0x110a.
- *   It is present in Ezra-T, Nehemiah and above.
- *   In addition to scaling multiplier, it can also scale voltage.
- *   There is provision for scaling FSB too, but this doesn't work
- *   too well in practice.
+ *   It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0.
+ *  Version 2 of longhaul is the same as v1, but adds voltage scaling.
+ *   Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C)
+ *   voltage scaling support has currently been disabled in this driver
+ *   until we have code that gets it right.
+ *  Version 3 of longhaul got renamed to Powersaver and redesigned
+ *   to use the POWERSAVER MSR at 0x110a.
+ *   It is present in Ezra-T (C5M), Nehemiah (C5X) and above.
+ *   It's pretty much the same feature wise to longhaul v2, though
+ *   there is provision for scaling FSB too, but this doesn't work
+ *   too well in practice so we don't even try to use this.
  *
  *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
  */
@@ -95,6 +100,26 @@
 }
 
 
+static void do_powersaver(int version)
+{
+	rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+	longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
+	longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
+	longhaul.bits.EnableSoftBusRatio = 1;
+	longhaul.bits.RevisionKey = 0;
+	local_irq_disable();
+	wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
+	local_irq_enable();
+	__hlt();
+
+	rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+	longhaul.bits.EnableSoftBusRatio = 0;
+	longhaul.bits.RevisionKey = version;
+	local_irq_disable();
+	wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+	local_irq_enable();
+}
+
 /**
  * longhaul_set_cpu_frequency()
  * @clock_ratio_index : bitpattern of the new multiplier.
@@ -126,61 +151,54 @@
 	dprintk (KERN_INFO PFX "FSB:%d Mult:%d.%dx\n", fsb, mult/10, mult%10);
 
 	switch (longhaul_version) {
+
+	/*
+	 * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B])
+	 * Software controlled multipliers only.
+	 *
+	 * *NB* Until we get voltage scaling working v1 & v2 are the same code.
+	 * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5b] and Ezra [C5C]
+	 */
 	case 1:
 		rdmsrl (MSR_VIA_BCR2, bcr2.val);
 		/* Enable software clock multiplier */
 		bcr2.bits.ESOFTBF = 1;
 		bcr2.bits.CLOCKMUL = clock_ratio_index;
+		local_irq_disable();
 		wrmsrl (MSR_VIA_BCR2, bcr2.val);
+		local_irq_enable();
 
 		__hlt();
 
 		/* Disable software clock multiplier */
 		rdmsrl (MSR_VIA_BCR2, bcr2.val);
 		bcr2.bits.ESOFTBF = 0;
+		local_irq_disable();
 		wrmsrl (MSR_VIA_BCR2, bcr2.val);
+		local_irq_enable();
 		break;
 
 	/*
-	 * Powersaver. (Ezra-T [C5M], Nehemiah [C5N])
+	 * Longhaul v3 (aka Powersaver). (Ezra-T [C5M])
 	 * We can scale voltage with this too, but that's currently
 	 * disabled until we come up with a decent 'match freq to voltage'
 	 * algorithm.
-	 * We also need to do the voltage/freq setting in order depending
-	 * on the direction of scaling (like we do in powernow-k7.c)
-	 * Ezra-T was alleged to do FSB scaling too, but it never worked in practice.
+	 * When we add voltage scaling, we will also need to do the
+	 * voltage/freq setting in order depending on the direction
+	 * of scaling (like we do in powernow-k7.c)
 	 */
 	case 2:
-		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-		longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
-		longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
-		longhaul.bits.EnableSoftBusRatio = 1;
-		/* We must program the revision key only with values we
-		 * know about, not blindly copy it from 0:3 */
-		longhaul.bits.RevisionKey = 3;	/* SoftVID & SoftBSEL */
-		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
-		__hlt();
-
-		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-		longhaul.bits.EnableSoftBusRatio = 0;
-		longhaul.bits.RevisionKey = 3;
-		wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+		do_powersaver(3);
 		break;
-	case 3:
-		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-		longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
-		longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
-		longhaul.bits.EnableSoftBusRatio = 1;
-
-		longhaul.bits.RevisionKey = 0x0;
-
-		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
-		__hlt();
 
-		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-		longhaul.bits.EnableSoftBusRatio = 0;
-		longhaul.bits.RevisionKey = 0xf;
-		wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+	/*
+	 * Powersaver. (Nehemiah [C5N])
+	 * As for Ezra-T, we don't do voltage yet.
+	 * This can do FSB scaling too, but it has never been proven
+	 * to work in practice.
+	 */
+	case 3:
+		do_powersaver(0xf);
 		break;
 	}
 
diff -Nru a/arch/i386/kernel/cpu/cpufreq/longrun.c b/arch/i386/kernel/cpu/cpufreq/longrun.c
--- a/arch/i386/kernel/cpu/cpufreq/longrun.c	2004-08-01 22:17:03 -07:00
+++ b/arch/i386/kernel/cpu/cpufreq/longrun.c	2004-08-01 22:17:03 -07:00
@@ -7,7 +7,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h> 
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/cpufreq.h>
@@ -19,7 +19,7 @@
 static struct cpufreq_driver	longrun_driver;
 
 /**
- * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz 
+ * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz
  * values into per cent values. In TMTA microcode, the following is valid:
  * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
  */
@@ -42,18 +42,18 @@
 		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
 	else
 		policy->policy = CPUFREQ_POLICY_POWERSAVE;
-	
+
 	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
 	msr_lo &= 0x0000007F;
 	msr_hi &= 0x0000007F;
-	
+
 	if ( longrun_high_freq <= longrun_low_freq ) {
 		/* Assume degenerate Longrun table */
 		policy->min = policy->max = longrun_high_freq;
 	} else {
-		policy->min = longrun_low_freq + msr_lo * 
+		policy->min = longrun_low_freq + msr_lo *
 			((longrun_high_freq - longrun_low_freq) / 100);
-		policy->max = longrun_low_freq + msr_hi * 
+		policy->max = longrun_low_freq + msr_hi *
 			((longrun_high_freq - longrun_low_freq) / 100);
 	}
 	policy->cpu = 0;
@@ -79,9 +79,9 @@
 		/* Assume degenerate Longrun table */
 		pctg_lo = pctg_hi = 100;
 	} else {
-		pctg_lo = (policy->min - longrun_low_freq) / 
+		pctg_lo = (policy->min - longrun_low_freq) /
 			((longrun_high_freq - longrun_low_freq) / 100);
-		pctg_hi = (policy->max - longrun_low_freq) / 
+		pctg_hi = (policy->max - longrun_low_freq) /
 			((longrun_high_freq - longrun_low_freq) / 100);
 	}
 
@@ -118,7 +118,7 @@
  * longrun_verify_poliy - verifies a new CPUFreq policy
  * @policy: the policy to verify
  *
- * Validates a new CPUFreq policy. This function has to be called with 
+ * Validates a new CPUFreq policy. This function has to be called with
  * cpufreq_driver locked.
  */
 static int longrun_verify_policy(struct cpufreq_policy *policy)
@@ -127,8 +127,8 @@
 		return -EINVAL;
 
 	policy->cpu = 0;
-	cpufreq_verify_within_limits(policy, 
-		policy->cpuinfo.min_freq, 
+	cpufreq_verify_within_limits(policy,
+		policy->cpuinfo.min_freq,
 		policy->cpuinfo.max_freq);
 
 	if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) &&
@@ -160,7 +160,7 @@
  * TMTA rules:
  * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
  */
-static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, 
+static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
 						   unsigned int *high_freq)
 {
 	u32 msr_lo, msr_hi;
@@ -174,9 +174,9 @@
 
 	if (cpu_has(c, X86_FEATURE_LRTI)) {
 		/* if the LongRun Table Interface is present, the
-		 * detection is a bit easier: 
+		 * detection is a bit easier:
 		 * For minimum frequency, read out the maximum
-		 * level (msr_hi), write that into "currently 
+		 * level (msr_hi), write that into "currently
 		 * selected level", and read out the frequency.
 		 * For maximum frequency, read out level zero.
 		 */
@@ -223,7 +223,7 @@
 		cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
 
 		/* restore values */
-		wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);	
+		wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);
 	}
 
 	/* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
@@ -237,7 +237,7 @@
 	if ((ecx > 95) || (ecx == 0) || (eax < ebx))
 		return -EIO;
 
-	edx = (eax - ebx) / (100 - ecx); 
+	edx = (eax - ebx) / (100 - ecx);
 	*low_freq = edx * 1000; /* back to kHz */
 
 	if (*low_freq > *high_freq)
@@ -249,7 +249,7 @@
 
 static int __init longrun_cpu_init(struct cpufreq_policy *policy)
 {
-	int                     result = 0;
+	int result = 0;
 
 	/* capability check */
 	if (policy->cpu != 0)
@@ -265,15 +265,15 @@
 	policy->cpuinfo.max_freq = longrun_high_freq;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	longrun_get_policy(policy);
-	
+
 	return 0;
 }
 
 
 static struct cpufreq_driver longrun_driver = {
 	.flags		= CPUFREQ_CONST_LOOPS,
-	.verify 	= longrun_verify_policy,
-	.setpolicy 	= longrun_set_policy,
+	.verify		= longrun_verify_policy,
+	.setpolicy	= longrun_set_policy,
 	.get		= longrun_get,
 	.init		= longrun_cpu_init,
 	.name		= "longrun",
@@ -290,7 +290,7 @@
 {
 	struct cpuinfo_x86 *c = cpu_data;
 
-	if (c->x86_vendor != X86_VENDOR_TRANSMETA || 
+	if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
 	    !cpu_has(c, X86_FEATURE_LONGRUN))
 		return -ENODEV;
 
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	2004-08-01 22:17:03 -07:00
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	2004-08-01 22:17:03 -07:00
@@ -6,8 +6,6 @@
  *  Licensed under the terms of the GNU GPL License version 2.
  *  Based upon datasheets & sample CPUs kindly provided by AMD.
  *
- *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
- *
  * Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt.
  * - We cli/sti on stepping A0 CPUs around the FID/VID transition.
  * Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect.
@@ -29,21 +27,13 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 #include <linux/acpi.h>
 #include <acpi/processor.h>
 #endif
 
 #include "powernow-k7.h"
 
-#define DEBUG
-
-#ifdef DEBUG
-#define dprintk(msg...) printk(msg)
-#else
-#define dprintk(msg...) do { } while(0)
-#endif
-
 #define PFX "powernow: "
 
 
@@ -64,7 +54,7 @@
 	u8 numpstates;
 };
 
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 union powernow_acpi_control_t {
 	struct {
 		unsigned long fid:5,
@@ -97,6 +87,7 @@
  */
 
 static int acpi_force;
+static int debug;
 
 static struct cpufreq_frequency_table *powernow_table;
 
@@ -109,6 +100,21 @@
 static unsigned int latency;
 static char have_a0;
 
+static void dprintk(const char *fmt, ...)
+{
+	char s[256];
+	va_list args;
+
+	if (debug==0)
+		return;
+
+	va_start(args,fmt);
+	vsprintf(s, fmt, args);
+	printk(s);
+	va_end(args);
+}
+
+
 static int check_fsb(unsigned int fsbspeed)
 {
 	int delta;
@@ -190,13 +196,13 @@
 		speed = powernow_table[j].frequency;
 
 		if ((fid_codes[fid] % 10)==5) {
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 			if (have_a0 == 1)
 				powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID;
 #endif
 		}
 
-		dprintk (KERN_INFO PFX "   FID: 0x%x (%d.%dx [%dMHz])\t", fid,
+		dprintk (KERN_INFO PFX "   FID: 0x%x (%d.%dx [%dMHz])  ", fid,
 			fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000);
 
 		if (speed < minimum_speed)
@@ -285,7 +291,7 @@
 		change_VID(vid);
 		change_FID(fid);
 	}
-	
+
 
 	if (have_a0 == 1)
 		local_irq_enable();
@@ -294,7 +300,7 @@
 }
 
 
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 
 struct acpi_processor_performance *acpi_processor_perf;
 
@@ -377,7 +383,7 @@
 				powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 		}
 
-		dprintk (KERN_INFO PFX "   FID: 0x%x (%d.%dx [%dMHz])\t", fid,
+		dprintk (KERN_INFO PFX "   FID: 0x%x (%d.%dx [%dMHz])  ", fid,
 			fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000);
 		dprintk ("VID: 0x%x (%d.%03dV)\n", vid,	mobile_vid_table[vid]/1000,
 			mobile_vid_table[vid]%1000);
@@ -467,9 +473,9 @@
 				    (maxfid==pst->maxfid) && (startvid==pst->startvid))
 				{
 					dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst);
-					dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid);
-					dprintk ("fsb: %d\t", pst->fsbspeed);
-					dprintk ("maxFID: 0x%x\t", pst->maxfid);
+					dprintk (KERN_INFO PFX " cpuid: 0x%x  ", pst->cpuid);
+					dprintk ("fsb: %d  ", pst->fsbspeed);
+					dprintk ("maxFID: 0x%x  ", pst->maxfid);
 					dprintk ("startvid: 0x%x\n", pst->startvid);
 
 					ret = get_ranges ((char *) pst + sizeof (struct pst_s));
@@ -591,14 +597,14 @@
 	rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
 
 	/* A K7 with powernow technology is set to max frequency by BIOS */
-	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
+	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID];
 	if (!fsb) {
 		printk(KERN_WARNING PFX "can not determine bus frequency\n");
 		return -EINVAL;
 	}
 	dprintk(KERN_INFO PFX "FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000);
 
- 	if (dmi_check_system(powernow_dmi_table) || acpi_force) {
+	if (dmi_check_system(powernow_dmi_table) || acpi_force) {
 		printk (KERN_INFO PFX "PSB/PST known to be broken.  Trying ACPI instead\n");
 		result = powernow_acpi_init();
 	} else {
@@ -648,14 +654,14 @@
 };
 
 static struct cpufreq_driver powernow_driver = {
-	.verify 	= powernow_verify,
-	.target 	= powernow_target,
-	.get		= powernow_get,	
-	.init		= powernow_cpu_init,
-	.exit		= powernow_cpu_exit,
-	.name		= "powernow-k7",
-	.owner		= THIS_MODULE,
-	.attr		= powernow_table_attr,
+	.verify	= powernow_verify,
+	.target	= powernow_target,
+	.get	= powernow_get,
+	.init	= powernow_cpu_init,
+	.exit	= powernow_cpu_exit,
+	.name	= "powernow-k7",
+	.owner	= THIS_MODULE,
+	.attr	= powernow_table_attr,
 };
 
 static int __init powernow_init (void)
@@ -668,7 +674,7 @@
 
 static void __exit powernow_exit (void)
 {
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 	if (acpi_processor_perf) {
 		acpi_processor_unregister_performance(acpi_processor_perf, 0);
 		kfree(acpi_processor_perf);
@@ -679,8 +685,10 @@
 		kfree(powernow_table);
 }
 
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "enable debug output.");
 module_param(acpi_force,  int, 0444);
-MODULE_PARM_DESC(acpi_force, "Force ACPI to be used");
+MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
 
 MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
 MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2004-08-01 22:17:03 -07:00
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2004-08-01 22:17:03 -07:00
@@ -32,7 +32,7 @@
 #include <asm/io.h>
 #include <asm/delay.h>
 
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K8_ACPI
 #include <linux/acpi.h>
 #include <acpi/processor.h>
 #endif
@@ -664,7 +664,7 @@
 	return -ENODEV;
 }
 
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K8_ACPI
 static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index)
 {
 	if (!data->acpi_data.state_count)
@@ -1024,7 +1024,7 @@
 	return -ENODEV;
 }
 
-static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol)
+static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
 {
 	struct powernow_k8_data *data = powernow_data[pol->cpu];
 
@@ -1076,7 +1076,7 @@
 	.verify = powernowk8_verify,
 	.target = powernowk8_target,
 	.init = powernowk8_cpu_init,
-	.exit = powernowk8_cpu_exit,
+	.exit = __devexit_p(powernowk8_cpu_exit),
 	.get = powernowk8_get,
 	.name = "powernow-k8",
 	.owner = THIS_MODULE,
diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c	2004-08-01 22:17:03 -07:00
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c	2004-08-01 22:17:03 -07:00
@@ -60,6 +60,13 @@
 	.x86_mask = 1,
 };
 
+static const struct cpu_id cpu_id_dothan_b0 = {
+	.x86_vendor = X86_VENDOR_INTEL,
+	.x86 = 6,
+	.x86_model = 13,
+	.x86_mask = 6,
+};
+
 struct cpu_model
 {
 	const struct cpu_id *cpu_id;
@@ -400,7 +407,8 @@
 		return -ENODEV;
 
 	if ((centrino_verify_cpu_id(cpu, &cpu_id_banias)) &&
-	    (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1))) {
+	    (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1)) &&
+		(centrino_verify_cpu_id(cpu, &cpu_id_dothan_b0))) {
 		printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
 		       "send /proc/cpuinfo to " MAINTAINER "\n");
 		return -ENODEV;
diff -Nru a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig
--- a/arch/x86_64/kernel/cpufreq/Kconfig	2004-08-01 22:17:03 -07:00
+++ b/arch/x86_64/kernel/cpufreq/Kconfig	2004-08-01 22:17:03 -07:00
@@ -41,4 +41,9 @@
 
 	  If in doubt, say N.
 
+config X86_POWERNOW_K8_ACPI
+	bool
+	depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
+	default y
+
 endmenu
diff -Nru a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
--- a/drivers/cpufreq/cpufreq.c	2004-08-01 22:17:03 -07:00
+++ b/drivers/cpufreq/cpufreq.c	2004-08-01 22:17:03 -07:00
@@ -100,6 +100,86 @@
 }
 
 /*********************************************************************
+ *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
+ *********************************************************************/
+
+/**
+ * adjust_jiffies - adjust the system "loops_per_jiffy"
+ *
+ * This function alters the system "loops_per_jiffy" for the clock
+ * speed change. Note that loops_per_jiffy cannot be updated on SMP
+ * systems as each CPU might be scaled differently. So, use the arch 
+ * per-CPU loops_per_jiffy value wherever possible.
+ */
+#ifndef CONFIG_SMP
+static unsigned long l_p_j_ref;
+static unsigned int  l_p_j_ref_freq;
+
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
+{
+	if (ci->flags & CPUFREQ_CONST_LOOPS)
+		return;
+
+	if (!l_p_j_ref_freq) {
+		l_p_j_ref = loops_per_jiffy;
+		l_p_j_ref_freq = ci->old;
+	}
+	if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
+	    (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
+	    (val == CPUFREQ_RESUMECHANGE))
+		loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
+}
+#else
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
+#endif
+
+
+/**
+ * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition
+ *
+ * This function calls the transition notifiers and the "adjust_jiffies" function. It is called
+ * twice on all CPU frequency changes that have external effects. 
+ */
+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
+{
+	BUG_ON(irqs_disabled());
+
+	freqs->flags = cpufreq_driver->flags;
+
+	down_read(&cpufreq_notifier_rwsem);
+	switch (state) {
+	case CPUFREQ_PRECHANGE:
+		/* detect if the driver reported a value as "old frequency" which
+		 * is not equal to what the cpufreq core thinks is "old frequency".
+		 */
+		if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
+			if ((likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
+			    (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
+			{
+				if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC)
+					panic("CPU Frequency is out of sync.");
+
+				printk(KERN_WARNING "Warning: CPU frequency is %u, "
+				       "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur);
+				freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
+			}
+		}
+		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
+		adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
+		break;
+	case CPUFREQ_POSTCHANGE:
+		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
+		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
+		cpufreq_cpu_data[freqs->cpu]->cur = freqs->new;
+		break;
+	}
+	up_read(&cpufreq_notifier_rwsem);
+}
+EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
+
+
+
+/*********************************************************************
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
 
@@ -617,8 +697,8 @@
 			if (cpufreq_driver->flags & CPUFREQ_PANIC_RESUME_OUTOFSYNC)
 				panic("CPU Frequency is out of sync.");
 
-			printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing"
-			       "core thinks of %u, is %u kHz.\n", cpu_policy->cur, cur_freq);
+			printk(KERN_WARNING "Warning: CPU frequency is %u, "
+			       "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur);
 
 			freqs.cpu = cpu;
 			freqs.old = cpu_policy->cur;
@@ -626,6 +706,8 @@
 
 			notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs);
 			adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
+
+			cpu_policy->cur = cur_freq;
 		}
 	}
 
@@ -1003,87 +1085,6 @@
 	return ret;
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
-
-
-/*********************************************************************
- *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
- *********************************************************************/
-
-/**
- * adjust_jiffies - adjust the system "loops_per_jiffy"
- *
- * This function alters the system "loops_per_jiffy" for the clock
- * speed change. Note that loops_per_jiffy cannot be updated on SMP
- * systems as each CPU might be scaled differently. So, use the arch 
- * per-CPU loops_per_jiffy value wherever possible.
- */
-#ifndef CONFIG_SMP
-static unsigned long l_p_j_ref;
-static unsigned int  l_p_j_ref_freq;
-
-static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
-{
-	if (ci->flags & CPUFREQ_CONST_LOOPS)
-		return;
-
-	if (!l_p_j_ref_freq) {
-		l_p_j_ref = loops_per_jiffy;
-		l_p_j_ref_freq = ci->old;
-	}
-	if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
-	    (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
-	    (val == CPUFREQ_RESUMECHANGE))
-		loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
-}
-#else
-static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
-#endif
-
-
-/**
- * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition
- *
- * This function calls the transition notifiers and the "adjust_jiffies" function. It is called
- * twice on all CPU frequency changes that have external effects. 
- */
-void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
-{
-	BUG_ON(irqs_disabled());
-
-	freqs->flags = cpufreq_driver->flags;
-
-	down_read(&cpufreq_notifier_rwsem);
-	switch (state) {
-	case CPUFREQ_PRECHANGE:
-		/* detect if the driver reported a value as "old frequency" which
-		 * is not equal to what the cpufreq core thinks is "old frequency".
-		 */
-		if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
-			if ((likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
-			    (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
-			{
-				if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC)
-					panic("CPU Frequency is out of sync.");
-
-				printk(KERN_WARNING "Warning: CPU frequency out of sync: "
-				       "cpufreq and timing core thinks of %u, is %u kHz.\n", 
-				       cpufreq_cpu_data[freqs->cpu]->cur, freqs->old);
-				freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
-			}
-		}
-		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
-		adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
-		break;
-	case CPUFREQ_POSTCHANGE:
-		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
-		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
-		cpufreq_cpu_data[freqs->cpu]->cur = freqs->new;
-		break;
-	}
-	up_read(&cpufreq_notifier_rwsem);
-}
-EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
-
 
 
 /*********************************************************************
diff -Nru a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
--- a/drivers/cpufreq/cpufreq_userspace.c	2004-08-01 22:17:03 -07:00
+++ b/drivers/cpufreq/cpufreq_userspace.c	2004-08-01 22:17:03 -07:00
@@ -82,6 +82,13 @@
 {
         struct cpufreq_freqs *freq = data;
 
+	/* Don't update cur_freq if CPU is managed and we're
+	 * waking up: else we won't remember what frequency 
+	 * we need to set the CPU to.
+	 */
+	if (cpu_is_managed[freq->cpu] && (val == CPUFREQ_RESUMECHANGE))
+		return 0;
+
 	cpu_cur_freq[freq->cpu] = freq->new;
 
         return 0;
@@ -521,6 +528,9 @@
 			      CPUFREQ_RELATION_H);
 		else if (policy->min > cpu_cur_freq[cpu])
 			__cpufreq_driver_target(&current_policy[cpu], policy->min, 
+			      CPUFREQ_RELATION_L);
+		else
+			__cpufreq_driver_target(&current_policy[cpu], cpu_cur_freq[cpu],
 			      CPUFREQ_RELATION_L);
 		memcpy (&current_policy[cpu], policy, sizeof(struct cpufreq_policy));
 		up(&userspace_sem);