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

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/05/11 16:39:15-07:00 akpm@bix.(none) 
#   Merge bk://linux-dj.bkbits.net/cpufreq
#   into bix.(none):/usr/src/bk-cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/05/11 16:39:12-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/11 16:38:21-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-cpufreq
# 
# arch/x86_64/kernel/time.c
#   2004/05/11 16:38:18-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/05/11 16:38:18-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/11 13:01:27+01:00 davej@redhat.com 
#   [CPUFREQ] Nehemiah improvements for longhaul driver.
#   From Andreas Meisinger 
# 
# arch/i386/kernel/cpu/cpufreq/longhaul.h
#   2004/05/11 13:01:16+01:00 davej@redhat.com +154 -13
#   [CPUFREQ] Nehemiah improvements for longhaul driver.
#   From Andreas Meisinger 
# 
# arch/i386/kernel/cpu/cpufreq/longhaul.c
#   2004/05/11 13:01:16+01:00 davej@redhat.com +72 -7
#   [CPUFREQ] Nehemiah improvements for longhaul driver.
#   From Andreas Meisinger 
# 
# ChangeSet
#   2004/05/11 12:59:02+01:00 davej@redhat.com 
#   [CPUFREQ] Fix for longrun.c for degenerate case
#   From H. Peter Anvin
#   
#   I ran into a system the other day which had a Transmeta processor, but
#   configured in a degenerate, fixed-frequency configuration.  It crashed
#   booting Fedora Core 2 test 3 due to a division by zero in the longrun
#   cpufreq driver.
# 
# arch/i386/kernel/cpu/cpufreq/longrun.c
#   2004/05/11 12:58:55+01:00 davej@redhat.com +19 -9
#   [CPUFREQ] Fix for longrun.c for degenerate case
#   From H. Peter Anvin
#   
#   I ran into a system the other day which had a Transmeta processor, but
#   configured in a degenerate, fixed-frequency configuration.  It crashed
#   booting Fedora Core 2 test 3 due to a division by zero in the longrun
#   cpufreq driver.
# 
# ChangeSet
#   2004/05/11 12:57:45+01:00 davej@redhat.com 
#   [CPUFREQ] Avoid scheduling cpufreq_delayed_get_work() twice; but do call it a bit earlier.
# 
# arch/i386/kernel/timers/timer_tsc.c
#   2004/05/11 12:57:39+01:00 davej@redhat.com +7 -2
#   [CPUFREQ] Avoid scheduling cpufreq_delayed_get_work() twice; but do call it a bit earlier.
# 
# ChangeSet
#   2004/05/11 12:56:07+01:00 davej@redhat.com 
#   [CPUFREQ] Latency is in nanoseconds -- speedstep-centrino got it wrong
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
#   2004/05/11 12:56:01+01:00 davej@redhat.com +1 -1
#   [CPUFREQ] Latency is in nanoseconds -- speedstep-centrino got it wrong
# 
# ChangeSet
#   2004/05/11 12:37:15+01:00 davej@redhat.com 
#   [CPUFREQ] cpu_sibling_mask fixup.
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/05/11 12:32:59+01:00 davej@redhat.com +4 -10
#   [CPUFREQ] cpu_sibling_mask fixup.
# 
# ChangeSet
#   2004/05/11 00:11:04+01:00 davej@delerium.codemonkey.org.uk 
#   Merge delerium.codemonkey.org.uk:/mnt/nfs/neologic/bar/src/kernel/2.6/trees/bk-linus
#   into delerium.codemonkey.org.uk:/mnt/nfs/neologic/bar/src/kernel/2.6/trees/cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/05/11 00:10:50+01:00 davej@delerium.codemonkey.org.uk +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/10 12:02:16+01:00 davej@redhat.com 
#   [CPUFREQ] Warning fixes.
#   On sparc64:
#                                                                                                              
#   drivers/cpufreq/cpufreq.c: In function `cpufreq_add_dev':
#   drivers/cpufreq/cpufreq.c:394: warning: cast to pointer from integer of different size
#   drivers/cpufreq/cpufreq.c: In function `handle_update':
#   drivers/cpufreq/cpufreq.c:507: warning: cast from pointer to integer of different size
# 
# drivers/cpufreq/cpufreq.c
#   2004/05/10 12:02:11+01:00 davej@redhat.com +2 -2
#   [CPUFREQ] Warning fixes.
#   On sparc64:
#                                                                                                              
#   drivers/cpufreq/cpufreq.c: In function `cpufreq_add_dev':
#   drivers/cpufreq/cpufreq.c:394: warning: cast to pointer from integer of different size
#   drivers/cpufreq/cpufreq.c: In function `handle_update':
#   drivers/cpufreq/cpufreq.c:507: warning: cast from pointer to integer of different size
# 
# ChangeSet
#   2004/05/07 15:51:44+01:00 davej@redhat.com 
#   [CPUFREQ] Add support for Pentium M (Dothan) processors for p4-clockmod.
#   But warn loudly if anyone tries to use it -- you really should use speedstep-centrino
#   instead. On Dothans, the TSC is _not_ affected by TSC transitions (contrary
#   to Banias processors), so set the CPUFREQ_CONST_LOOPS flag.
#                                                                                   
#   Many thanks to Thomas Renninger for reporting the lack of, and testing
#   the support for Dothan processors.
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/05/07 15:51:37+01:00 davej@redhat.com +13 -1
#   [CPUFREQ] Add support for Pentium M (Dothan) processors for p4-clockmod.
#   But warn loudly if anyone tries to use it -- you really should use speedstep-centrino
#   instead. On Dothans, the TSC is _not_ affected by TSC transitions (contrary
#   to Banias processors), so set the CPUFREQ_CONST_LOOPS flag.
#                                                                                   
#   Many thanks to Thomas Renninger for reporting the lack of, and testing
#   the support for Dothan processors.
# 
# ChangeSet
#   2004/05/07 15:50:34+01:00 davej@redhat.com 
#   [CPUFREQ] Add support for Pentium M (Dothan) processors.
#   Until further review, only ACPI data will get this driver to run - no built-in tables will exist.
#                                                                                   
#   Many thanks to Thomas Renninger for reporting the lack of, and testing
#   the support for Dothan processors.
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
#   2004/05/07 15:50:29+01:00 davej@redhat.com +9 -4
#   [CPUFREQ] Add support for Pentium M (Dothan) processors.
#   Until further review, only ACPI data will get this driver to run - no built-in tables will exist.
#                                                                                   
#   Many thanks to Thomas Renninger for reporting the lack of, and testing
#   the support for Dothan processors.
# 
# ChangeSet
#   2004/05/07 15:49:11+01:00 davej@redhat.com 
#   [CPUFREQ] Improved Banias detection.
#   The built-in tables are only valid for Pentium M (Banias) processors
#   with CPUID 6/9/5. So, add a pointer to the proper struct cpu_id to the
#   cpu_model struct, and re-name _CPU/CPU to _BANIAS/BANIAS
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
#   2004/05/07 15:49:06+01:00 davej@redhat.com +40 -32
#   [CPUFREQ] Improved Banias detection.
#   The built-in tables are only valid for Pentium M (Banias) processors
#   with CPUID 6/9/5. So, add a pointer to the proper struct cpu_id to the
#   cpu_model struct, and re-name _CPU/CPU to _BANIAS/BANIAS
# 
# ChangeSet
#   2004/05/07 15:47:29+01:00 davej@redhat.com 
#   [CPUFREQ] Clean up P4 centrino detection.
#   Add a new "struct cpu_id" for better handling of different Pentium M
#   steppings / revisions.
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
#   2004/05/07 15:47:24+01:00 davej@redhat.com +26 -4
#   [CPUFREQ] Clean up P4 centrino detection.
#   Add a new "struct cpu_id" for better handling of different Pentium M
#   steppings / revisions.
# 
# ChangeSet
#   2004/05/07 15:45:54+01:00 davej@redhat.com 
#   [CPUFREQ] Handle P4 TSC scaling.
#   Currently, the TSC cpufreq notifiers does almost nothing on P4s, as we
#   assumed the TSC to be constant independent of _all_ frequency transitions.
#   Extensive testing by Karol Kozimor has shown, though, that only _throttling_
#   does not affect the TSC, but _scaling_ does.
#                                                                                   
#   So:
#   - pass the CPUFREQ_CONST_LOOPS flags (to be exact, all flags) to cpufreq
#     transition notifiers
#   - skip TSC value changes if this flag is set
#   - set this flag for P4 / P4-Ms only in p4-clockmod [On Pentium-M banias
#     the TSC _is_ affected by p4-clock modulation
# 
# include/linux/cpufreq.h
#   2004/05/07 15:45:48+01:00 davej@redhat.com +1 -0
#   [CPUFREQ] Handle P4 TSC scaling.
#   Currently, the TSC cpufreq notifiers does almost nothing on P4s, as we
#   assumed the TSC to be constant independent of _all_ frequency transitions.
#   Extensive testing by Karol Kozimor has shown, though, that only _throttling_
#   does not affect the TSC, but _scaling_ does.
#                                                                                   
#   So:
#   - pass the CPUFREQ_CONST_LOOPS flags (to be exact, all flags) to cpufreq
#     transition notifiers
#   - skip TSC value changes if this flag is set
#   - set this flag for P4 / P4-Ms only in p4-clockmod [On Pentium-M banias
#     the TSC _is_ affected by p4-clock modulation
# 
# drivers/cpufreq/cpufreq.c
#   2004/05/07 15:45:48+01:00 davej@redhat.com +3 -1
#   [CPUFREQ] Handle P4 TSC scaling.
#   Currently, the TSC cpufreq notifiers does almost nothing on P4s, as we
#   assumed the TSC to be constant independent of _all_ frequency transitions.
#   Extensive testing by Karol Kozimor has shown, though, that only _throttling_
#   does not affect the TSC, but _scaling_ does.
#                                                                                   
#   So:
#   - pass the CPUFREQ_CONST_LOOPS flags (to be exact, all flags) to cpufreq
#     transition notifiers
#   - skip TSC value changes if this flag is set
#   - set this flag for P4 / P4-Ms only in p4-clockmod [On Pentium-M banias
#     the TSC _is_ affected by p4-clock modulation
# 
# arch/i386/kernel/timers/timer_tsc.c
#   2004/05/07 15:45:48+01:00 davej@redhat.com +8 -12
#   [CPUFREQ] Handle P4 TSC scaling.
#   Currently, the TSC cpufreq notifiers does almost nothing on P4s, as we
#   assumed the TSC to be constant independent of _all_ frequency transitions.
#   Extensive testing by Karol Kozimor has shown, though, that only _throttling_
#   does not affect the TSC, but _scaling_ does.
#                                                                                   
#   So:
#   - pass the CPUFREQ_CONST_LOOPS flags (to be exact, all flags) to cpufreq
#     transition notifiers
#   - skip TSC value changes if this flag is set
#   - set this flag for P4 / P4-Ms only in p4-clockmod [On Pentium-M banias
#     the TSC _is_ affected by p4-clock modulation
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/05/07 15:45:48+01:00 davej@redhat.com +5 -0
#   [CPUFREQ] Handle P4 TSC scaling.
#   Currently, the TSC cpufreq notifiers does almost nothing on P4s, as we
#   assumed the TSC to be constant independent of _all_ frequency transitions.
#   Extensive testing by Karol Kozimor has shown, though, that only _throttling_
#   does not affect the TSC, but _scaling_ does.
#                                                                                   
#   So:
#   - pass the CPUFREQ_CONST_LOOPS flags (to be exact, all flags) to cpufreq
#     transition notifiers
#   - skip TSC value changes if this flag is set
#   - set this flag for P4 / P4-Ms only in p4-clockmod [On Pentium-M banias
#     the TSC _is_ affected by p4-clock modulation
# 
# ChangeSet
#   2004/05/07 15:44:21+01:00 davej@redhat.com 
#   [CPUFREQ] Also check whether the CPU frequency is out of sync once we get to cpufreq_notify_transition.
# 
# drivers/cpufreq/cpufreq.c
#   2004/05/07 15:44:11+01:00 davej@redhat.com +16 -1
#   [CPUFREQ] Also check whether the CPU frequency is out of sync once we get to cpufreq_notify_transition.
# 
# ChangeSet
#   2004/05/07 15:43:19+01:00 davej@redhat.com 
#   [CPUFREQ] Handle CPU frequency changing behind our back.
#   Once we detected 50 consecutive ticks with lost ticks (and this is half of
#   the amount needed to trigger the fallback to a "sane" timesource), verify
#   the CPU frequency is in sync if cpufreq is used: sometimes the CPU frequency
#   changes behind the user's back, and then the TSC detects lost ticks. By a
#   call to cpufreq_get(), the frequency the TSC driver thinks the CPU is in
#   is updated to the actual frequency, in case these differ. Works really nice
#   on my notebook -- it's never falling back to a different timesource now, even
#   if I plug in the power cord.
# 
# arch/i386/kernel/timers/timer_tsc.c
#   2004/05/07 15:43:14+01:00 davej@redhat.com +32 -0
#   [CPUFREQ] Handle CPU frequency changing behind our back.
#   Once we detected 50 consecutive ticks with lost ticks (and this is half of
#   the amount needed to trigger the fallback to a "sane" timesource), verify
#   the CPU frequency is in sync if cpufreq is used: sometimes the CPU frequency
#   changes behind the user's back, and then the TSC detects lost ticks. By a
#   call to cpufreq_get(), the frequency the TSC driver thinks the CPU is in
#   is updated to the actual frequency, in case these differ. Works really nice
#   on my notebook -- it's never falling back to a different timesource now, even
#   if I plug in the power cord.
# 
# ChangeSet
#   2004/05/07 15:41:58+01:00 davej@redhat.com 
#   [CPUFREQ] sa11x0 ->get
#   sa11x0_getspeed can be used by both cpu-sa1100.c and cpu-sa1110.c as
#   ->get() function. Update calling conventions, and un-export it as
#   we fixed the handling of cpufreq_get in the cpufreq core. Also,
#   remove special call to userspace-governor init as it isn't needed
#   any longer.
#   
# 
# arch/arm/mach-sa1100/generic.h
#   2004/05/07 15:41:50+01:00 davej@redhat.com +1 -1
#   [CPUFREQ] sa11x0 ->get
#   sa11x0_getspeed can be used by both cpu-sa1100.c and cpu-sa1110.c as
#   ->get() function. Update calling conventions, and un-export it as
#   we fixed the handling of cpufreq_get in the cpufreq core. Also,
#   remove special call to userspace-governor init as it isn't needed
#   any longer.
#   
# 
# arch/arm/mach-sa1100/generic.c
#   2004/05/07 15:41:50+01:00 davej@redhat.com +4 -2
#   [CPUFREQ] sa11x0 ->get
#   sa11x0_getspeed can be used by both cpu-sa1100.c and cpu-sa1110.c as
#   ->get() function. Update calling conventions, and un-export it as
#   we fixed the handling of cpufreq_get in the cpufreq core. Also,
#   remove special call to userspace-governor init as it isn't needed
#   any longer.
#   
# 
# arch/arm/mach-sa1100/cpu-sa1110.c
#   2004/05/07 15:41:50+01:00 davej@redhat.com +5 -4
#   [CPUFREQ] sa11x0 ->get
#   sa11x0_getspeed can be used by both cpu-sa1100.c and cpu-sa1110.c as
#   ->get() function. Update calling conventions, and un-export it as
#   we fixed the handling of cpufreq_get in the cpufreq core. Also,
#   remove special call to userspace-governor init as it isn't needed
#   any longer.
#   
# 
# arch/arm/mach-sa1100/cpu-sa1100.c
#   2004/05/07 15:41:50+01:00 davej@redhat.com +5 -3
#   [CPUFREQ] sa11x0 ->get
#   sa11x0_getspeed can be used by both cpu-sa1100.c and cpu-sa1110.c as
#   ->get() function. Update calling conventions, and un-export it as
#   we fixed the handling of cpufreq_get in the cpufreq core. Also,
#   remove special call to userspace-governor init as it isn't needed
#   any longer.
#   
# 
# ChangeSet
#   2004/05/07 15:40:59+01:00 davej@redhat.com 
#   [CPUFREQ] arm-integrator ->get() implementation 
#   arm-integrator had its ->get() implementation inside
#   integrator_cpufreq_init(). Move it to an extra function,
#   and add it as ->get() function.
# 
# arch/arm/mach-integrator/cpu.c
#   2004/05/07 15:40:53+01:00 davej@redhat.com +14 -6
#   [CPUFREQ] arm-integrator ->get() implementation 
#   arm-integrator had its ->get() implementation inside
#   integrator_cpufreq_init(). Move it to an extra function,
#   and add it as ->get() function.
# 
# ChangeSet
#   2004/05/07 15:38:00+01:00 davej@redhat.com 
#   [CPUFREQ] Use speedstep_lib's capabilites for ->get() in speedstep-smi.c
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
#   2004/05/07 15:37:52+01:00 davej@redhat.com +17 -3
#   [CPUFREQ] Use speedstep_lib's capabilites for ->get() in speedstep-smi.c
# 
# ChangeSet
#   2004/05/07 15:37:05+01:00 davej@redhat.com 
#   [CPUFREQ] Use speedstep_lib's capabilites for ->get() in speedstep-ich.c
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
#   2004/05/07 15:36:59+01:00 davej@redhat.com +5 -0
#   [CPUFREQ] Use speedstep_lib's capabilites for ->get() in speedstep-ich.c
# 
# ChangeSet
#   2004/05/07 15:36:26+01:00 davej@redhat.com 
#   [CPUFREQ] use speedstep_centrino's internal get function as ->get()
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
#   2004/05/07 15:36:20+01:00 davej@redhat.com +6 -3
#   [CPUFREQ] use speedstep_centrino's internal get function as ->get()
# 
# ChangeSet
#   2004/05/07 15:35:39+01:00 davej@redhat.com 
#   [CPUFREQ] Add powernowk8_get()
#   but be careful as some code needs to run on specified CPU only.
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/05/07 15:35:33+01:00 davej@redhat.com +27 -0
#   [CPUFREQ] Add powernowk8_get()
#   but be careful as some code needs to run on specified CPU only.
# 
# ChangeSet
#   2004/05/07 15:34:15+01:00 davej@redhat.com 
#   [CPUFREQ] powernow-k7->get() implementation by Bruno Ducrot.
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/05/07 15:34:07+01:00 davej@redhat.com +16 -1
#   [CPUFREQ] powernow-k7->get() implementation by Bruno Ducrot.
# 
# ChangeSet
#   2004/05/07 15:33:10+01:00 davej@redhat.com 
#   [CPUFREQ] powernow-k6 ->get
#   powernow_k6 has almost all pieces in place for its own ->get() function.
#   Add the rest.
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k6.c
#   2004/05/07 15:33:03+01:00 davej@redhat.com +6 -0
#   [CPUFREQ] powernow-k6 ->get
#   powernow_k6 has almost all pieces in place for its own ->get() function.
#   Add the rest.
# 
# ChangeSet
#   2004/05/07 15:32:21+01:00 davej@redhat.com 
#   [CPUFREQ] Add p4-clockmod ->get
#   p4-clockmod is a bit more complicated as it might run on SMP, HT, and
#   the instructions need to run on the specific (physical) CPU.
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/05/07 15:32:15+01:00 davej@redhat.com +38 -0
#   [CPUFREQ] Add p4-clockmod ->get
#   p4-clockmod is a bit more complicated as it might run on SMP, HT, and
#   the instructions need to run on the specific (physical) CPU.
# 
# ChangeSet
#   2004/05/07 15:31:46+01:00 davej@redhat.com 
#   [CPUFREQ] Add longrun ->get
#   Longrun users might be interested in their CPU's current frequency as
#   well, so use a longrun-specific cpuid-call in longrun_get().
# 
# arch/i386/kernel/cpu/cpufreq/longrun.c
#   2004/05/07 15:31:40+01:00 davej@redhat.com +13 -0
#   [CPUFREQ] Add longrun ->get
#   Longrun users might be interested in their CPU's current frequency as
#   well, so use a longrun-specific cpuid-call in longrun_get().
# 
# ChangeSet
#   2004/05/07 15:29:19+01:00 davej@redhat.com 
#   [CPUFREQ] Add a longhaul_get function.
# 
# arch/i386/kernel/cpu/cpufreq/longhaul.c
#   2004/05/07 15:29:14+01:00 davej@redhat.com +8 -0
#   [CPUFREQ] Add a longhaul_get function.
# 
# ChangeSet
#   2004/05/07 15:18:53+01:00 davej@redhat.com 
#   [CPUFREQ] use gx-suspmod's internal get function as ->get()
# 
# arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
#   2004/05/07 15:18:48+01:00 davej@redhat.com +5 -4
#   [CPUFREQ] use gx-suspmod's internal get function as ->get()
# 
# ChangeSet
#   2004/05/07 15:18:13+01:00 davej@redhat.com 
#   [CPUFREQ] use elanfreq's internal get function as ->get()
# 
# arch/i386/kernel/cpu/cpufreq/elanfreq.c
#   2004/05/07 15:18:07+01:00 davej@redhat.com +5 -4
#   [CPUFREQ] use elanfreq's internal get function as ->get()
# 
# ChangeSet
#   2004/05/07 15:17:28+01:00 davej@redhat.com 
#   [CPUFREQ] Handle CPUFREQ_RESUMECHANGE notifications
#   Notifications in i386, sparc64, x86_64, sh-sci and sa11xx-pcmcia notifiers.
#   sa1100-framebuffer doesn't seem to be able to handle frequency transitions
#   behind its back well. So, sa11xx will be marked
#   CPUFREQ_PANIC_OUTOFSYNC | CPUFREQ_PANIC_RESUME_OUTOFSYNC later.
# 
# drivers/serial/sh-sci.c
#   2004/05/07 15:17:22+01:00 davej@redhat.com +2 -1
#   [CPUFREQ] Handle CPUFREQ_RESUMECHANGE notifications
#   Notifications in i386, sparc64, x86_64, sh-sci and sa11xx-pcmcia notifiers.
#   sa1100-framebuffer doesn't seem to be able to handle frequency transitions
#   behind its back well. So, sa11xx will be marked
#   CPUFREQ_PANIC_OUTOFSYNC | CPUFREQ_PANIC_RESUME_OUTOFSYNC later.
# 
# drivers/pcmcia/sa11xx_core.c
#   2004/05/07 15:17:22+01:00 davej@redhat.com +2 -0
#   [CPUFREQ] Handle CPUFREQ_RESUMECHANGE notifications
#   Notifications in i386, sparc64, x86_64, sh-sci and sa11xx-pcmcia notifiers.
#   sa1100-framebuffer doesn't seem to be able to handle frequency transitions
#   behind its back well. So, sa11xx will be marked
#   CPUFREQ_PANIC_OUTOFSYNC | CPUFREQ_PANIC_RESUME_OUTOFSYNC later.
# 
# drivers/char/sh-sci.c
#   2004/05/07 15:17:22+01:00 davej@redhat.com +2 -1
#   [CPUFREQ] Handle CPUFREQ_RESUMECHANGE notifications
#   Notifications in i386, sparc64, x86_64, sh-sci and sa11xx-pcmcia notifiers.
#   sa1100-framebuffer doesn't seem to be able to handle frequency transitions
#   behind its back well. So, sa11xx will be marked
#   CPUFREQ_PANIC_OUTOFSYNC | CPUFREQ_PANIC_RESUME_OUTOFSYNC later.
# 
# arch/x86_64/kernel/time.c
#   2004/05/07 15:17:22+01:00 davej@redhat.com +2 -1
#   [CPUFREQ] Handle CPUFREQ_RESUMECHANGE notifications
#   Notifications in i386, sparc64, x86_64, sh-sci and sa11xx-pcmcia notifiers.
#   sa1100-framebuffer doesn't seem to be able to handle frequency transitions
#   behind its back well. So, sa11xx will be marked
#   CPUFREQ_PANIC_OUTOFSYNC | CPUFREQ_PANIC_RESUME_OUTOFSYNC later.
# 
# arch/sparc64/kernel/time.c
#   2004/05/07 15:17:21+01:00 davej@redhat.com +2 -1
#   [CPUFREQ] Handle CPUFREQ_RESUMECHANGE notifications
#   Notifications in i386, sparc64, x86_64, sh-sci and sa11xx-pcmcia notifiers.
#   sa1100-framebuffer doesn't seem to be able to handle frequency transitions
#   behind its back well. So, sa11xx will be marked
#   CPUFREQ_PANIC_OUTOFSYNC | CPUFREQ_PANIC_RESUME_OUTOFSYNC later.
# 
# arch/i386/kernel/timers/timer_tsc.c
#   2004/05/07 15:17:21+01:00 davej@redhat.com +2 -1
#   [CPUFREQ] Handle CPUFREQ_RESUMECHANGE notifications
#   Notifications in i386, sparc64, x86_64, sh-sci and sa11xx-pcmcia notifiers.
#   sa1100-framebuffer doesn't seem to be able to handle frequency transitions
#   behind its back well. So, sa11xx will be marked
#   CPUFREQ_PANIC_OUTOFSYNC | CPUFREQ_PANIC_RESUME_OUTOFSYNC later.
# 
# ChangeSet
#   2004/05/07 15:13:59+01:00 davej@redhat.com 
#   [CPUFREQ] (Hopefully) fix cpufreq resume support.
#    
#   Upon resuming, first CPUfreq hardware support needs to be re-enabled in certain cases
#   (call to cpufreq_driver->resume()).
#    
#   Then, two different paths may need to be taken:
#   a) frequency during suspend equals frequency during resume ==> everything is fine,
#    
#   b) frequency differ ==> either we can't handle it, then panic (see flag
#      CPUFREQ_PANIC_RESUME_OUTOFSYNC). Or we can handle it, then notify all
# 
# include/linux/cpufreq.h
#   2004/05/07 15:13:53+01:00 davej@redhat.com +5 -0
#   [CPUFREQ] (Hopefully) fix cpufreq resume support.
#    
#   Upon resuming, first CPUfreq hardware support needs to be re-enabled in certain cases
#   (call to cpufreq_driver->resume()).
#    
#   Then, two different paths may need to be taken:
#   a) frequency during suspend equals frequency during resume ==> everything is fine,
#    
#   b) frequency differ ==> either we can't handle it, then panic (see flag
#      CPUFREQ_PANIC_RESUME_OUTOFSYNC). Or we can handle it, then notify all
# 
# drivers/cpufreq/cpufreq.c
#   2004/05/07 15:13:53+01:00 davej@redhat.com +38 -25
#   [CPUFREQ] (Hopefully) fix cpufreq resume support.
#    
#   Upon resuming, first CPUfreq hardware support needs to be re-enabled in certain cases
#   (call to cpufreq_driver->resume()).
#    
#   Then, two different paths may need to be taken:
#   a) frequency during suspend equals frequency during resume ==> everything is fine,
#    
#   b) frequency differ ==> either we can't handle it, then panic (see flag
#      CPUFREQ_PANIC_RESUME_OUTOFSYNC). Or we can handle it, then notify all
# 
# Documentation/cpu-freq/core.txt
#   2004/05/07 15:13:53+01:00 davej@redhat.com +4 -0
#   [CPUFREQ] (Hopefully) fix cpufreq resume support.
#    
#   Upon resuming, first CPUfreq hardware support needs to be re-enabled in certain cases
#   (call to cpufreq_driver->resume()).
#    
#   Then, two different paths may need to be taken:
#   a) frequency during suspend equals frequency during resume ==> everything is fine,
#    
#   b) frequency differ ==> either we can't handle it, then panic (see flag
#      CPUFREQ_PANIC_RESUME_OUTOFSYNC). Or we can handle it, then notify all
# 
# ChangeSet
#   2004/05/07 15:11:44+01:00 davej@redhat.com 
#   [CPUFREQ] Fix 'out of sync' issue.
#   Sometimes we might discover during a call to cpufreq_get() that we're "out of sync",
#   meaning the actual CPU frequency changed "behind our back". If this happens, the flag
#   CPUFREQ_PANIC_OUTOFSYNC decides what can be done: if it is set, the kernel panic's,
#   it it is not set, the cpufreq transition notifiers are informed of this change, and
#   a call to cpufreq_update_policy() is scheduled [using the default workqueue] so that
#   the user-defined values override BIOS / external interaction.
# 
# include/linux/cpufreq.h
#   2004/05/07 15:11:38+01:00 davej@redhat.com +13 -2
#   [CPUFREQ] Fix 'out of sync' issue.
#   Sometimes we might discover during a call to cpufreq_get() that we're "out of sync",
#   meaning the actual CPU frequency changed "behind our back". If this happens, the flag
#   CPUFREQ_PANIC_OUTOFSYNC decides what can be done: if it is set, the kernel panic's,
#   it it is not set, the cpufreq transition notifiers are informed of this change, and
#   a call to cpufreq_update_policy() is scheduled [using the default workqueue] so that
#   the user-defined values override BIOS / external interaction.
# 
# drivers/cpufreq/cpufreq.c
#   2004/05/07 15:11:37+01:00 davej@redhat.com +50 -0
#   [CPUFREQ] Fix 'out of sync' issue.
#   Sometimes we might discover during a call to cpufreq_get() that we're "out of sync",
#   meaning the actual CPU frequency changed "behind our back". If this happens, the flag
#   CPUFREQ_PANIC_OUTOFSYNC decides what can be done: if it is set, the kernel panic's,
#   it it is not set, the cpufreq transition notifiers are informed of this change, and
#   a call to cpufreq_update_policy() is scheduled [using the default workqueue] so that
#   the user-defined values override BIOS / external interaction.
# 
# ChangeSet
#   2004/05/07 15:09:07+01:00 davej@redhat.com 
#   [CPUFREQ] Export cpufreq_get() to userspace.
#   As it involves calls to hardware which might take some time,
#   only let the super-user read out this value.
# 
# drivers/cpufreq/cpufreq.c
#   2004/05/07 15:09:02+01:00 davej@redhat.com +21 -0
#   [CPUFREQ] Export cpufreq_get() to userspace.
#   As it involves calls to hardware which might take some time,
#   only let the super-user read out this value.
# 
# ChangeSet
#   2004/05/07 15:08:05+01:00 davej@redhat.com 
#   [CPUFREQ] Move cpufreq_get() from the userspace governor to the core.
#   Contrary to the previous implementation, it now calls the cpufreq driver,
#   and reads out the _actual_ current frequency, and not the frequency the
#   CPUfreq core _thinks_ the CPU is running at. Most cpufreq drivers do provide
#   such a "hw get" function (only ACPI-io can definitely not be supported,
#   I'm not sure about sh, sparc64 and powermac) anyway, and it is useful for
#   other issues.
# 
# include/linux/cpufreq.h
#   2004/05/07 15:07:59+01:00 davej@redhat.com +6 -3
#   [CPUFREQ] Move cpufreq_get() from the userspace governor to the core.
#   Contrary to the previous implementation, it now calls the cpufreq driver,
#   and reads out the _actual_ current frequency, and not the frequency the
#   CPUfreq core _thinks_ the CPU is running at. Most cpufreq drivers do provide
#   such a "hw get" function (only ACPI-io can definitely not be supported,
#   I'm not sure about sh, sparc64 and powermac) anyway, and it is useful for
#   other issues.
# 
# drivers/cpufreq/cpufreq_userspace.c
#   2004/05/07 15:07:59+01:00 davej@redhat.com +3 -39
#   [CPUFREQ] Move cpufreq_get() from the userspace governor to the core.
#   Contrary to the previous implementation, it now calls the cpufreq driver,
#   and reads out the _actual_ current frequency, and not the frequency the
#   CPUfreq core _thinks_ the CPU is running at. Most cpufreq drivers do provide
#   such a "hw get" function (only ACPI-io can definitely not be supported,
#   I'm not sure about sh, sparc64 and powermac) anyway, and it is useful for
#   other issues.
# 
# drivers/cpufreq/cpufreq.c
#   2004/05/07 15:07:59+01:00 davej@redhat.com +32 -0
#   [CPUFREQ] Move cpufreq_get() from the userspace governor to the core.
#   Contrary to the previous implementation, it now calls the cpufreq driver,
#   and reads out the _actual_ current frequency, and not the frequency the
#   CPUfreq core _thinks_ the CPU is running at. Most cpufreq drivers do provide
#   such a "hw get" function (only ACPI-io can definitely not be supported,
#   I'm not sure about sh, sparc64 and powermac) anyway, and it is useful for
#   other issues.
# 
# ChangeSet
#   2004/05/07 15:06:16+01:00 davej@redhat.com 
#   [CPUFREQ] Export scaling cur frequencies
#   Many users want to know the current cpu freqeuncy, even if not using
#   the userspace frequency. On ->target cpufreq drivers (if they do their
#   calls to cpufreq_notify_transition correctly) this just means reading
#   out cpufreq_policy->cur.
# 
# drivers/cpufreq/cpufreq.c
#   2004/05/07 15:06:11+01:00 davej@redhat.com +4 -0
#   [CPUFREQ] Export scaling cur frequencies
#   Many users want to know the current cpu freqeuncy, even if not using
#   the userspace frequency. On ->target cpufreq drivers (if they do their
#   calls to cpufreq_notify_transition correctly) this just means reading
#   out cpufreq_policy->cur.
# 
# ChangeSet
#   2004/04/22 16:09:05+01:00 davej@redhat.com 
#   [CPUFREQ] powernow-k8: prevent BIOSs offering a vid of 0x1f, which means off.
#   From paul.devriendt@amd.com
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/04/22 16:08:59+01:00 davej@redhat.com +7 -0
#   [CPUFREQ] powernow-k8: prevent BIOSs offering a vid of 0x1f, which means off.
#   From paul.devriendt@amd.com
# 
# ChangeSet
#   2004/04/22 16:05:21+01:00 davej@redhat.com 
#   [CPUFREQ] powernow-k8 ignore invalid p-states.
#   From paul.devriendt@amd.com
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/04/22 16:05:16+01:00 davej@redhat.com +7 -6
#   [CPUFREQ] powernow-k8 ignore invalid p-states.
#   From paul.devriendt@amd.com
# 
# ChangeSet
#   2004/04/22 16:01:36+01:00 davej@redhat.com 
#   [CPUFREQ] powernow-k8 cpuid changes.
#   cpuid changes to support new processors that will be coming out in the
#   future. Also works around a processor that we have released to the field
#   that can have an erroneous cpuid value.
#   
#   From paul.devriendt@amd.com
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.h
#   2004/04/22 16:01:29+01:00 davej@redhat.com +9 -7
#   [CPUFREQ] powernow-k8 cpuid changes.
#   cpuid changes to support new processors that will be coming out in the
#   future. Also works around a processor that we have released to the field
#   that can have an erroneous cpuid value.
#   
#   From paul.devriendt@amd.com
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/04/22 16:01:29+01:00 davej@redhat.com +5 -8
#   [CPUFREQ] powernow-k8 cpuid changes.
#   cpuid changes to support new processors that will be coming out in the
#   future. Also works around a processor that we have released to the field
#   that can have an erroneous cpuid value.
#   
#   From paul.devriendt@amd.com
# 
# ChangeSet
#   2004/04/13 10:02:09-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/Kconfig
#   2004/04/13 10:02:06-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/04/12 20:52:00-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/Kconfig
#   2004/04/12 20:51:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
diff -Nru a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt
--- a/Documentation/cpu-freq/core.txt	Wed May 12 20:27:23 2004
+++ b/Documentation/cpu-freq/core.txt	Wed May 12 20:27:23 2004
@@ -92,3 +92,7 @@
 cpu	- number of the affected CPU
 old	- old frequency
 new	- new frequency
+
+If the cpufreq core detects the frequency has changed while the system
+was suspended, these notifiers are called with CPUFREQ_RESUMECHANGE as
+second argument.
diff -Nru a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
--- a/arch/arm/mach-integrator/cpu.c	Wed May 12 20:27:23 2004
+++ b/arch/arm/mach-integrator/cpu.c	Wed May 12 20:27:23 2004
@@ -152,10 +152,10 @@
 	return 0;
 }
 
-static int integrator_cpufreq_init(struct cpufreq_policy *policy)
+static unsigned int integrator_get(unsigned int cpu)
 {
 	unsigned long cpus_allowed;
-	unsigned int cpu = policy->cpu;
+	unsigned int current_freq;
 	u_int cm_osc;
 	struct icst525_vco vco;
 
@@ -175,15 +175,22 @@
 	vco.v = cm_osc & 255;
 	vco.r = 22;
 
+	current_freq = icst525_khz(&cclk_params, vco); /* current freq */
+
+	set_cpus_allowed(current, cpus_allowed);
+
+	return current_freq;
+}
+
+static int integrator_cpufreq_init(struct cpufreq_policy *policy)
+{
+
 	/* set default policy and cpuinfo */
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.max_freq = 160000;
 	policy->cpuinfo.min_freq = 12000;
 	policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
-	policy->cur = policy->min = policy->max =
-		icst525_khz(&cclk_params, vco); /* current freq */
-
-	set_cpus_allowed(current, cpus_allowed);
+	policy->cur = policy->min = policy->max = integrator_get(policy->cpu);
 
 	return 0;
 }
@@ -191,6 +198,7 @@
 static struct cpufreq_driver integrator_driver = {
 	.verify		= integrator_verify_policy,
 	.target		= integrator_set_target,
+	.get		= integrator_get,
 	.init		= integrator_cpufreq_init,
 	.name		= "integrator",
 };
diff -Nru a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c
--- a/arch/arm/mach-sa1100/cpu-sa1100.c	Wed May 12 20:27:23 2004
+++ b/arch/arm/mach-sa1100/cpu-sa1100.c	Wed May 12 20:27:23 2004
@@ -180,7 +180,7 @@
 			 unsigned int target_freq,
 			 unsigned int relation)
 {
-	unsigned int cur = sa11x0_getspeed();
+	unsigned int cur = sa11x0_getspeed(0);
 	unsigned int new_ppcr;
 
 	struct cpufreq_freqs freqs;
@@ -221,7 +221,7 @@
 {
 	if (policy->cpu != 0)
 		return -EINVAL;
-	policy->cur = policy->min = policy->max = sa11x0_getspeed();
+	policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.min_freq = 59000;
 	policy->cpuinfo.max_freq = 287000;
@@ -230,15 +230,17 @@
 }
 
 static struct cpufreq_driver sa1100_driver = {
+	.flags		= (CPUFREQ_PANIC_OUTOFSYNC | 
+			   CPUFREQ_PANIC_RESUME_OUTOFSYNC),
 	.verify		= sa11x0_verify_speed,
 	.target		= sa1100_target,
+	.get		= sa11x0_getspeed,
 	.init		= sa1100_cpu_init,
 	.name		= "sa1100",
 };
 
 static int __init sa1100_dram_init(void)
 {
-	cpufreq_gov_userspace_init();
  	if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID)
 		return cpufreq_register_driver(&sa1100_driver);
 	else
diff -Nru a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
--- a/arch/arm/mach-sa1100/cpu-sa1110.c	Wed May 12 20:27:23 2004
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c	Wed May 12 20:27:23 2004
@@ -238,7 +238,7 @@
 		return -EINVAL;
 	}
 
-	freqs.old = sa11x0_getspeed();
+	freqs.old = sa11x0_getspeed(0);
 	freqs.new = sa11x0_ppcr_to_freq(ppcr);
 	freqs.cpu = 0;
 
@@ -320,7 +320,7 @@
 {
 	if (policy->cpu != 0)
 		return -EINVAL;
-	policy->cur = policy->min = policy->max = sa11x0_getspeed();
+	policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.min_freq = 59000;
 	policy->cpuinfo.max_freq = 287000;
@@ -329,8 +329,11 @@
 }
 
 static struct cpufreq_driver sa1110_driver = {
+	.flags		= (CPUFREQ_PANIC_OUTOFSYNC | 
+			   CPUFREQ_PANIC_RESUME_OUTOFSYNC),
 	.verify		= sa11x0_verify_speed,
 	.target		= sa1110_target,
+	.get		= sa11x0_getspeed,
 	.init		= sa1110_cpu_init,
 	.name		= "sa1110",
 };
@@ -354,8 +357,6 @@
 			sdram->tck, sdram->trcd, sdram->trp,
 			sdram->twr, sdram->refresh, sdram->cas_latency);
 
-		cpufreq_gov_userspace_init();
- 
 		memcpy(&sdram_params, sdram, sizeof(sdram_params));
 
 		return cpufreq_register_driver(&sa1110_driver);
diff -Nru a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
--- a/arch/arm/mach-sa1100/generic.c	Wed May 12 20:27:23 2004
+++ b/arch/arm/mach-sa1100/generic.c	Wed May 12 20:27:23 2004
@@ -96,11 +96,13 @@
 	return 0;
 }
 
-unsigned int sa11x0_getspeed(void)
+unsigned int sa11x0_getspeed(unsigned int cpu)
 {
+	if (cpu)
+		return 0;
 	return cclk_frequency_100khz[PPCR & 0xf] * 100;
 }
-EXPORT_SYMBOL(sa11x0_getspeed);
+
 #else
 /*
  * We still need to provide this so building without cpufreq works.
diff -Nru a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
--- a/arch/arm/mach-sa1100/generic.h	Wed May 12 20:27:23 2004
+++ b/arch/arm/mach-sa1100/generic.h	Wed May 12 20:27:23 2004
@@ -22,5 +22,5 @@
 
 extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
 extern int sa11x0_verify_speed(struct cpufreq_policy *policy);
-extern unsigned int sa11x0_getspeed(void);
+extern unsigned int sa11x0_getspeed(unsigned int cpu);
 extern unsigned int sa11x0_ppcr_to_freq(unsigned int idx);
diff -Nru a/arch/i386/kernel/cpu/cpufreq/elanfreq.c b/arch/i386/kernel/cpu/cpufreq/elanfreq.c
--- a/arch/i386/kernel/cpu/cpufreq/elanfreq.c	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/elanfreq.c	Wed May 12 20:27:23 2004
@@ -77,7 +77,7 @@
  *	and have the rest of the chip running with 33 MHz. 
  */
 
-static unsigned int elanfreq_get_cpu_frequency(void)
+static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
 {
         u8 clockspeed_reg;    /* Clock Speed Register */
 	
@@ -121,7 +121,7 @@
 
 	struct cpufreq_freqs    freqs;
 
-	freqs.old = elanfreq_get_cpu_frequency();
+	freqs.old = elanfreq_get_cpu_frequency(0);
 	freqs.new = elan_multiplier[state].clock;
 	freqs.cpu = 0; /* elanfreq.c is UP only driver */
 	
@@ -209,7 +209,7 @@
 
 	/* max freq */
 	if (!max_freq)
-		max_freq = elanfreq_get_cpu_frequency();
+		max_freq = elanfreq_get_cpu_frequency(0);
 
 	/* table init */
  	for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
@@ -220,7 +220,7 @@
 	/* cpuinfo and default policy values */
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-	policy->cur = elanfreq_get_cpu_frequency();
+	policy->cur = elanfreq_get_cpu_frequency(0);
 
 	result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table);
 	if (result)
@@ -267,6 +267,7 @@
 
 
 static struct cpufreq_driver elanfreq_driver = {
+	.get	 	= elanfreq_get_cpu_frequency,
 	.verify 	= elanfreq_verify,
 	.target 	= elanfreq_target,
 	.init		= elanfreq_cpu_init,
diff -Nru a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
--- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c	Wed May 12 20:27:23 2004
@@ -215,7 +215,7 @@
  *
  * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi Geode CPU runs.
  */
-static int gx_get_cpuspeed(void)
+static unsigned int gx_get_cpuspeed(unsigned int cpu)
 {
 	if ((gx_params->pci_suscfg & SUSMOD) == 0) 
 		return stock_freq;
@@ -271,7 +271,7 @@
 
 
 	freqs.cpu = 0;
-	freqs.old = gx_get_cpuspeed();
+	freqs.old = gx_get_cpuspeed(0);
 
 	new_khz = gx_validate_speed(khz, &gx_params->on_duration, &gx_params->off_duration);
 
@@ -405,7 +405,7 @@
 
 static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
 {
-	int maxfreq, curfreq;
+	unsigned int maxfreq, curfreq;
 
 	if (!policy || policy->cpu != 0)
 		return -ENODEV;
@@ -419,7 +419,7 @@
 		maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
 	}
 	stock_freq = maxfreq;
-	curfreq = gx_get_cpuspeed();
+	curfreq = gx_get_cpuspeed(0);
 
 	dprintk("cpu max frequency is %d.\n", maxfreq);
 	dprintk("cpu current frequency is %dkHz.\n",curfreq);
@@ -446,6 +446,7 @@
  *   MediaGX/Geode GX initialize cpufreq driver
  */
 static struct cpufreq_driver gx_suspmod_driver = {
+	.get		= gx_get_cpuspeed,
 	.verify		= cpufreq_gx_verify,
 	.target		= cpufreq_gx_target,
 	.init		= cpufreq_gx_cpu_init,
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	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c	Wed May 12 20:27:23 2004
@@ -82,6 +82,10 @@
 		if (lo & (1<<27))
 			invalue+=16;
 	}
+	if (longhaul_version==4) {
+		if (lo & (1<<27))
+			invalue+=16;
+	}
 	return eblcr_table[invalue];
 }
 
@@ -158,6 +162,22 @@
 		longhaul.bits.RevisionKey = 3;
 		wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
 		break;
+	case 4:
+		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);		
+		break;
 	}
 
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -207,7 +227,7 @@
 static int __init longhaul_get_ranges (void)
 {
 	struct cpuinfo_x86 *c = cpu_data;
-	unsigned long invalue;
+	unsigned long invalue,invalue2;
 	unsigned int minmult=0, maxmult=0;
 	unsigned int multipliers[32]= {
 		50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
@@ -234,8 +254,6 @@
 	case 2:
 		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
 
-		//TODO: Nehemiah may have borken MaxMHzBR.
-		// need to extrapolate from FSB.
 		invalue = longhaul.bits.MaxMHzBR;
 		if (longhaul.bits.MaxMHzBR4)
 			invalue += 16;
@@ -258,6 +276,38 @@
 				break;
 		}
 		break;
+		
+	case 4:
+		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+		
+		//TODO: Nehemiah may have borken MaxMHzBR.
+		// need to extrapolate from FSB.
+		
+		invalue2 = longhaul.bits.MinMHzBR;
+		invalue = longhaul.bits.MaxMHzBR;
+		if (longhaul.bits.MaxMHzBR4) 
+			invalue += 16;
+		maxmult=multipliers[invalue];
+		
+		maxmult=longhaul_get_cpu_mult();
+		
+		printk(KERN_INFO PFX " invalue: %ld  maxmult: %d \n", invalue, maxmult);
+		printk(KERN_INFO PFX " invalue2: %ld \n", invalue2);
+		
+		minmult=50;
+		
+		switch (longhaul.bits.MaxMHzFSB) {
+		case 0x0:	fsb=133;
+				break;
+		case 0x1:	fsb=100;
+				break;
+		case 0x2:	printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");
+			return -EINVAL;
+		case 0x3:	fsb=66;
+				break;
+		}
+		
+		break;	
 	}
 
 	dprintk (KERN_INFO PFX "MinMult=%d.%dx MaxMult=%d.%dx\n",
@@ -380,6 +430,13 @@
 	return 0;
 }
 
+static unsigned int longhaul_get(unsigned int cpu)
+{
+	if (cpu)
+		return 0;
+	return (calc_speed (longhaul_get_cpu_mult(), fsb));
+}
+
 static int __init longhaul_cpu_init (struct cpufreq_policy *policy)
 {
 	struct cpuinfo_x86 *c = cpu_data;
@@ -423,12 +480,27 @@
 		break;
 
 	case 9:
-		cpuname = "C3 'Nehemiah' [C5N]";
-		longhaul_version=2;
+		longhaul_version=4;
 		numscales=32;
-		memcpy (clock_ratio, nehemiah_clock_ratio, sizeof(nehemiah_clock_ratio));
-		memcpy (eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));
+		switch (c->x86_mask) {
+		case 0 ... 1:
+			cpuname = "C3 'Nehemiah A' [C5N]";
+			memcpy (clock_ratio, nehemiah_a_clock_ratio, sizeof(nehemiah_a_clock_ratio));
+			memcpy (eblcr_table, nehemiah_a_eblcr, sizeof(nehemiah_a_eblcr));
+			break;
+		case 2 ... 4:
+			cpuname = "C3 'Nehemiah B' [C5N]";
+			memcpy (clock_ratio, nehemiah_b_clock_ratio, sizeof(nehemiah_b_clock_ratio));
+			memcpy (eblcr_table, nehemiah_b_eblcr, sizeof(nehemiah_b_eblcr));
+			break;
+		case 5 ... 15:
+			cpuname = "C3 'Nehemiah C' [C5N]";
+			memcpy (clock_ratio, nehemiah_c_clock_ratio, sizeof(nehemiah_c_clock_ratio));
+			memcpy (eblcr_table, nehemiah_c_eblcr, sizeof(nehemiah_c_eblcr));
+			break;
+		}
 		break;
+		
 
 	default:
 		cpuname = "Unknown";
@@ -472,6 +544,7 @@
 static struct cpufreq_driver longhaul_driver = {
 	.verify 	= longhaul_verify,
 	.target 	= longhaul_target,
+	.get 		= longhaul_get,
 	.init		= longhaul_cpu_init,
 	.exit		= longhaul_cpu_exit,
 	.name		= "longhaul",
diff -Nru a/arch/i386/kernel/cpu/cpufreq/longhaul.h b/arch/i386/kernel/cpu/cpufreq/longhaul.h
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.h	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.h	Wed May 12 20:27:23 2004
@@ -234,14 +234,15 @@
 
 /*
  * VIA C3 Nehemiah */
-static int __initdata nehemiah_clock_ratio[32] = {
+ 
+static int __initdata nehemiah_a_clock_ratio[32] = {
 	100, /* 0000 -> 10.0x */
 	160, /* 0001 -> 16.0x */
-	-1,  /* 0010 -> RESERVED */
+	-1,  /* 0010 ->  RESERVED */
 	90,  /* 0011 ->  9.0x */
 	95,  /* 0100 ->  9.5x */
-	-1,  /* 0101 -> RESERVED */
-	-1,  /* 0110 -> RESERVED */
+	-1,  /* 0101 ->  RESERVED */
+	-1,  /* 0110 ->  RESERVED */
 	55,  /* 0111 ->  5.5x */
 	60,  /* 1000 ->  6.0x */
 	70,  /* 1001 ->  7.0x */
@@ -250,8 +251,77 @@
 	65,  /* 1100 ->  6.5x */
 	75,  /* 1101 ->  7.5x */
 	85,  /* 1110 ->  8.5x */
-	120, /* 1111 ->  12.0x */
+	120, /* 1111 -> 12.0x */
+	100, /* 0000 -> 10.0x */
+	-1,  /* 0001 -> RESERVED */
+	120, /* 0010 -> 12.0x */
+	90,  /* 0011 ->  9.0x */
+	105, /* 0100 -> 10.5x */
+	115, /* 0101 -> 11.5x */
+	125, /* 0110 -> 12.5x */
+	135, /* 0111 -> 13.5x */
+	140, /* 1000 -> 14.0x */
+	150, /* 1001 -> 15.0x */
+	160, /* 1010 -> 16.0x */
+	130, /* 1011 -> 13.0x */
+	145, /* 1100 -> 14.5x */
+	155, /* 1101 -> 15.5x */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	120, /* 1111 -> 12.0x */
+};
+
+static int __initdata  nehemiah_b_clock_ratio[32] = {
+	100, /* 0000 -> 10.0x */
+	160, /* 0001 -> 16.0x */
+	-1,  /* 0010 ->  RESERVED */
+	90,  /* 0011 ->  9.0x */
+	95,  /* 0100 ->  9.5x */
+	-1,  /* 0101 ->  RESERVED */
+	-1,  /* 0110 ->  RESERVED */
+	55,  /* 0111 ->  5.5x */
+	60,  /* 1000 ->  6.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	50,  /* 1011 ->  5.0x */
+	65,  /* 1100 ->  6.5x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	120, /* 1111 -> 12.0x */
+	100, /* 0000 -> 10.0x */
+	110, /* 0001 -> 11.0x */
+	120, /* 0010 -> 12.0x */
+	90,  /* 0011 ->  9.0x */
+	105, /* 0100 -> 10.5x */
+	115, /* 0101 -> 11.5x */
+	125, /* 0110 -> 12.5x */
+	135, /* 0111 -> 13.5x */
+	140, /* 1000 -> 14.0x */
+	150, /* 1001 -> 15.0x */
+	160, /* 1010 -> 16.0x */
+	130, /* 1011 -> 13.0x */
+	145, /* 1100 -> 14.5x */
+	155, /* 1101 -> 15.5x */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	120, /* 1111 -> 12.0x */
+};
 
+static int __initdata  nehemiah_c_clock_ratio[32] = {
+	100, /* 0000 -> 10.0x */
+	160, /* 0001 -> 16.0x */
+	40,  /* 0010 ->  RESERVED */
+	90,  /* 0011 ->  9.0x */
+	95,  /* 0100 ->  9.5x */
+	-1,  /* 0101 ->  RESERVED */
+	45,  /* 0110 ->  RESERVED */
+	55,  /* 0111 ->  5.5x */
+	60,  /* 1000 ->  6.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	50,  /* 1011 ->  5.0x */
+	65,  /* 1100 ->  6.5x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	120, /* 1111 -> 12.0x */
 	100, /* 0000 -> 10.0x */
 	110, /* 0001 -> 11.0x */
 	120, /* 0010 -> 12.0x */
@@ -266,18 +336,53 @@
 	130, /* 1011 -> 13.0x */
 	145, /* 1100 -> 14.5x */
 	155, /* 1101 -> 15.5x */
-	-1,  /* 1110 -> RESERVED */
+	-1,  /* 1110 -> RESERVED (13.0x) */
 	120, /* 1111 -> 12.0x */
 };
 
-static int __initdata nehemiah_eblcr[32] = {
+static int __initdata nehemiah_a_eblcr[32] = {
 	50,  /* 0000 ->  5.0x */
 	160, /* 0001 -> 16.0x */
-	-1,  /* 0010 -> RESERVED */
+	-1,  /* 0010 ->  RESERVED */
 	100, /* 0011 -> 10.0x */
 	55,  /* 0100 ->  5.5x */
-	-1,  /* 0101 -> RESERVED */
-	-1,  /* 0110 -> RESERVED */
+	-1,  /* 0101 ->  RESERVED */
+	-1,  /* 0110 ->  RESERVED */
+	95,  /* 0111 ->  9.5x */
+	90,  /* 1000 ->  9.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	60,  /* 1011 ->  6.0x */
+	120, /* 1100 -> 12.0x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	65,  /* 1111 ->  6.5x */
+	90,  /* 0000 ->  9.0x */
+	-1,  /* 0001 -> RESERVED */
+	120, /* 0010 -> 12.0x */
+	100, /* 0011 -> 10.0x */
+	135, /* 0100 -> 13.5x */
+	115, /* 0101 -> 11.5x */
+	125, /* 0110 -> 12.5x */
+	105, /* 0111 -> 10.5x */
+	130, /* 1000 -> 13.0x */
+	150, /* 1001 -> 15.0x */
+	160, /* 1010 -> 16.0x */
+	140, /* 1011 -> 14.0x */
+	120, /* 1100 -> 12.0x */
+	155, /* 1101 -> 15.5x */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	145 /* 1111 -> 14.5x */
+   /* end of table  */
+};
+static int __initdata nehemiah_b_eblcr[32] = {
+	50,  /* 0000 ->  5.0x */
+	160, /* 0001 -> 16.0x */
+	-1,  /* 0010 ->  RESERVED */
+	100, /* 0011 -> 10.0x */
+	55,  /* 0100 ->  5.5x */
+	-1,  /* 0101 ->  RESERVED */
+	-1,  /* 0110 ->  RESERVED */
 	95,  /* 0111 ->  9.5x */
 	90,  /* 1000 ->  9.0x */
 	70,  /* 1001 ->  7.0x */
@@ -287,7 +392,6 @@
 	75,  /* 1101 ->  7.5x */
 	85,  /* 1110 ->  8.5x */
 	65,  /* 1111 ->  6.5x */
-
 	90,  /* 0000 ->  9.0x */
 	110, /* 0001 -> 11.0x */
 	120, /* 0010 -> 12.0x */
@@ -302,9 +406,46 @@
 	140, /* 1011 -> 14.0x */
 	120, /* 1100 -> 12.0x */
 	155, /* 1101 -> 15.5x */
-	-1,  /* 1110 -> RESERVED */
-	-1,  /* 1111 -> RESERVED */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	145 /* 1111 -> 14.5x */
+	   /* end of table  */
 };
+static int __initdata nehemiah_c_eblcr[32] = {
+	50,  /* 0000 ->  5.0x */
+	160, /* 0001 -> 16.0x */
+	40,  /* 0010 ->  RESERVED */
+	100, /* 0011 -> 10.0x */
+	55,  /* 0100 ->  5.5x */
+	-1,  /* 0101 ->  RESERVED */
+	45,  /* 0110 ->  RESERVED */
+	95,  /* 0111 ->  9.5x */
+	90,  /* 1000 ->  9.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	60,  /* 1011 ->  6.0x */
+	120, /* 1100 -> 12.0x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	65,  /* 1111 ->  6.5x */
+	90,  /* 0000 ->  9.0x */
+	110, /* 0001 -> 11.0x */
+	120, /* 0010 -> 12.0x */
+	100, /* 0011 -> 10.0x */
+	135, /* 0100 -> 13.5x */
+	115, /* 0101 -> 11.5x */
+	125, /* 0110 -> 12.5x */
+	105, /* 0111 -> 10.5x */
+	130, /* 1000 -> 13.0x */
+	150, /* 1001 -> 15.0x */
+	160, /* 1010 -> 16.0x */
+	140, /* 1011 -> 14.0x */
+	120, /* 1100 -> 12.0x */
+	155, /* 1101 -> 15.5x */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	145 /* 1111 -> 14.5x */
+	  /* end of table  */
+};
+
 /* 
  * Voltage scales. Div/Mod by 1000 to get actual voltage.
  * Which scale to use depends on the VRM type in use.
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	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/longrun.c	Wed May 12 20:27:23 2004
@@ -46,11 +46,16 @@
 	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
 	msr_lo &= 0x0000007F;
 	msr_hi &= 0x0000007F;
-
-	policy->min = longrun_low_freq + msr_lo * 
-		((longrun_high_freq - longrun_low_freq) / 100);
-	policy->max = longrun_low_freq + msr_hi * 
-		((longrun_high_freq - longrun_low_freq) / 100);
+	
+	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 * 
+			((longrun_high_freq - longrun_low_freq) / 100);
+		policy->max = longrun_low_freq + msr_hi * 
+			((longrun_high_freq - longrun_low_freq) / 100);
+	}
 	policy->cpu = 0;
 }
 
@@ -70,10 +75,15 @@
 	if (!policy)
 		return -EINVAL;
 
-	pctg_lo = (policy->min - longrun_low_freq) / 
-		((longrun_high_freq - longrun_low_freq) / 100);
-	pctg_hi = (policy->max - longrun_low_freq) / 
-		((longrun_high_freq - longrun_low_freq) / 100);
+	if ( longrun_high_freq <= longrun_low_freq ) {
+		/* Assume degenerate Longrun table */
+		pctg_lo = pctg_hi = 100;
+	} else {
+		pctg_lo = (policy->min - longrun_low_freq) / 
+			((longrun_high_freq - longrun_low_freq) / 100);
+		pctg_hi = (policy->max - longrun_low_freq) / 
+			((longrun_high_freq - longrun_low_freq) / 100);
+	}
 
 	if (pctg_hi > 100)
 		pctg_hi = 100;
@@ -128,6 +138,17 @@
 	return 0;
 }
 
+static unsigned int longrun_get(unsigned int cpu)
+{
+	u32 eax, ebx, ecx, edx;
+
+	if (cpu)
+		return 0;
+
+	cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
+
+	return (eax * 1000);
+}
 
 /**
  * longrun_determine_freqs - determines the lowest and highest possible core frequency
@@ -250,8 +271,10 @@
 
 
 static struct cpufreq_driver longrun_driver = {
+	.flags		= CPUFREQ_CONST_LOOPS,
 	.verify 	= longrun_verify_policy,
 	.setpolicy 	= longrun_set_policy,
+	.get		= longrun_get,
 	.init		= longrun_cpu_init,
 	.name		= "longrun",
 	.owner		= THIS_MODULE,
diff -Nru a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
--- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Wed May 12 20:27:23 2004
@@ -51,6 +51,7 @@
 
 static int has_N44_O17_errata[NR_CPUS];
 static unsigned int stock_freq;
+static struct cpufreq_driver p4clockmod_driver;
 
 static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
 {
@@ -177,7 +178,7 @@
 static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
 {
 	if ((c->x86 == 0x06) && (c->x86_model == 0x09)) {
-		/* Pentium M */
+		/* Pentium M (Banias) */
 		printk(KERN_WARNING PFX "Warning: Pentium M detected. "
 		       "The speedstep_centrino module offers voltage scaling"
 		       " in addition of frequency scaling. You should use "
@@ -185,11 +186,27 @@
 		return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
 	}
 
+	if ((c->x86 == 0x06) && (c->x86_model == 0x13)) {
+		/* Pentium M (Dothan) */
+		printk(KERN_WARNING PFX "Warning: Pentium M detected. "
+		       "The speedstep_centrino module offers voltage scaling"
+		       " in addition of frequency scaling. You should use "
+		       "that instead of p4-clockmod, if possible.\n");
+		/* on P-4s, the TSC runs with constant frequency independent wether
+		 * throttling is active or not. */
+		p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
+		return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
+	}
+
 	if (c->x86 != 0xF) {
 		printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <linux@brodo.de>\n");
 		return 0;
 	}
 
+	/* on P-4s, the TSC runs with constant frequency independent wether
+	 * throttling is active or not. */
+	p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
+
 	if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) {
 		printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. "
 		       "The speedstep-ich or acpi cpufreq modules offer "
@@ -249,6 +266,37 @@
 	return 0;
 }
 
+static unsigned int cpufreq_p4_get(unsigned int cpu)
+{
+	cpumask_t cpus_allowed, affected_cpu_map;
+	u32 l, h;
+
+	/* only run on CPU to be set, or on its sibling */
+	cpus_allowed = current->cpus_allowed;
+#ifdef CONFIG_SMP
+        affected_cpu_map = cpu_sibling_map[cpu];
+#else
+        affected_cpu_map = cpumask_of_cpu(cpu);
+#endif
+	set_cpus_allowed(current, affected_cpu_map);
+        BUG_ON(!cpu_isset(smp_processor_id(), affected_cpu_map));
+
+	rdmsr(MSR_IA32_THERM_CONTROL, l, h);
+
+	set_cpus_allowed(current, cpus_allowed);
+
+	if (l & 0x10) {
+		l = l >> 1;
+		l &= 0x7;
+	} else
+		l = DC_DISABLE;
+
+	if (l != DC_DISABLE)
+		return (stock_freq * l / 8);
+
+	return stock_freq;
+}
+
 static struct freq_attr* p4clockmod_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
 	NULL,
@@ -259,6 +307,7 @@
 	.target		= cpufreq_p4_target,
 	.init		= cpufreq_p4_cpu_init,
 	.exit		= cpufreq_p4_cpu_exit,
+	.get		= cpufreq_p4_get,
 	.name		= "p4-clockmod",
 	.owner		= THIS_MODULE,
 	.attr		= p4clockmod_attr,
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c	Wed May 12 20:27:23 2004
@@ -185,6 +185,11 @@
  	return 0;
 }
 
+static unsigned int powernow_k6_get(unsigned int cpu)
+{
+	return busfreq * powernow_k6_get_cpu_multiplier();
+}
+
 static struct freq_attr* powernow_k6_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
 	NULL,
@@ -195,6 +200,7 @@
 	.target 	= powernow_k6_target,
 	.init		= powernow_k6_cpu_init,
 	.exit		= powernow_k6_cpu_exit,
+	.get		= powernow_k6_get,
 	.name		= "powernow-k6",
 	.owner		= THIS_MODULE,
 	.attr		= powernow_k6_attr,
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	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	Wed May 12 20:27:23 2004
@@ -540,6 +540,20 @@
 	return sgtc;
 }
 
+static unsigned int powernow_get(unsigned int cpu)
+{
+	union msr_fidvidstatus fidvidstatus;
+	unsigned int cfid;
+
+	if (cpu)
+		return 0;
+	rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
+	cfid = fidvidstatus.bits.CFID;
+
+	return (fsb * fid_codes[cfid] / 10);
+}
+
+
 static int __init powernow_cpu_init (struct cpufreq_policy *policy)
 {
 	union msr_fidvidstatus fidvidstatus;
@@ -590,7 +604,7 @@
 
 	policy->cpuinfo.transition_latency = 20 * latency / fsb;
 
-	policy->cur = maximum_speed;
+	policy->cur = powernow_get(0);
 
 	cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);
 
@@ -610,6 +624,7 @@
 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",
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	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	Wed May 12 20:27:23 2004
@@ -39,7 +39,7 @@
 
 #define PFX "powernow-k8: "
 #define BFX PFX "BIOS error: "
-#define VERSION "version 1.00.08b"
+#define VERSION "version 1.00.09b"
 #include "powernow-k8.h"
 
 /* serialize freq changes  */
@@ -450,13 +450,10 @@
 		goto out;
 
 	eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
-	if ((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) {
-		dprintk(KERN_DEBUG PFX "AMD Althon 64 Processor found\n");
-	} else if ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD) {
-		dprintk(KERN_DEBUG PFX "AMD Opteron Processor found\n");
-	} else {
-		printk(KERN_INFO PFX
-		       "AMD Athlon 64 or AMD Opteron processor required\n");
+	if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
+	    ((eax & CPUID_XFAM) != CPUID_XFAM_K8) ||
+	    ((eax & CPUID_XMOD) > CPUID_XMOD_REV_E)) {
+		printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
 		goto out;
 	}
 
@@ -524,11 +521,12 @@
 {
 	int j;
 	for (j = 0; j < data->numps; j++) {
-		printk(KERN_INFO PFX "   %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j,
-			data->powernow_table[j].index & 0xff,
-			data->powernow_table[j].frequency/1000,
-			data->powernow_table[j].index >> 8,
-			find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
+		if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID)
+			printk(KERN_INFO PFX "   %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j,
+				data->powernow_table[j].index & 0xff,
+				data->powernow_table[j].frequency/1000,
+				data->powernow_table[j].index >> 8,
+				find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
 	}
 	if (data->batps)
 		printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps);
@@ -723,7 +721,14 @@
 		/* verify frequency is OK */
 		if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) ||
 			(powernow_table[i].frequency < (MIN_FREQ * 1000))) {
-			dprintk(KERN_INFO PFX "invalid freq %u kHz\n", powernow_table[i].frequency);
+			dprintk(KERN_INFO PFX "invalid freq %u kHz, ignoring\n", powernow_table[i].frequency);
+			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+			continue;
+		}
+
+		/* verify voltage is OK - BIOSs are using "off" to indicate invalid */
+		if (vid == 0x1f) {
+			dprintk(KERN_INFO PFX "invalid vid %u, ignoring\n", vid);
 			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 			continue;
 		}
@@ -1025,6 +1030,32 @@
 	return 0;
 }
 
+static unsigned int powernowk8_get (unsigned int cpu)
+{
+	struct powernow_k8_data *data = powernow_data[cpu];
+	cpumask_t oldmask = current->cpus_allowed;
+	unsigned int khz = 0;
+
+	set_cpus_allowed(current, cpumask_of_cpu(cpu));
+	if (smp_processor_id() != cpu) {
+		printk(KERN_ERR PFX "limiting to CPU %d failed in powernowk8_get\n", cpu);
+		set_cpus_allowed(current, oldmask);
+		return 0;
+	}
+	preempt_disable();
+
+	if (query_current_values_with_pending_wait(data))
+		goto out;
+
+	khz = find_khz_freq_from_fid(data->currfid);	
+
+ out:
+	preempt_enable_no_resched();
+	set_cpus_allowed(current, oldmask);
+
+	return khz;
+}
+
 static struct freq_attr* powernow_k8_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
 	NULL,
@@ -1035,6 +1066,7 @@
 	.target = powernowk8_target,
 	.init = powernowk8_cpu_init,
 	.exit = powernowk8_cpu_exit,
+	.get = powernowk8_get,
 	.name = "powernow-k8",
 	.owner = THIS_MODULE,
 	.attr = powernow_k8_attr,
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h	Wed May 12 20:27:23 2004
@@ -38,13 +38,15 @@
 
 
 /* processor's cpuid instruction support */
-#define CPUID_PROCESSOR_SIGNATURE             1	/* function 1 */
-#define CPUID_XFAM_MOD               0x0ff00ff0	/* extended fam, fam + model */
-#define ATHLON64_XFAM_MOD            0x00000f40	/* extended fam, fam + model */
-#define OPTERON_XFAM_MOD             0x00000f50	/* extended fam, fam + model */
-#define CPUID_GET_MAX_CAPABILITIES   0x80000000
-#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007
-#define P_STATE_TRANSITION_CAPABLE            6
+#define CPUID_PROCESSOR_SIGNATURE	1	/* function 1 */
+#define CPUID_XFAM			0x0ff00000	/* extended family */
+#define CPUID_XFAM_K8			0
+#define CPUID_XMOD			0x000f0000	/* extended model */
+#define CPUID_XMOD_REV_E		0x00020000
+#define CPUID_USE_XFAM_XMOD		0x00000f00
+#define CPUID_GET_MAX_CAPABILITIES	0x80000000
+#define CPUID_FREQ_VOLT_CAPABILITIES	0x80000007
+#define P_STATE_TRANSITION_CAPABLE	6
 
 /* Model Specific Registers for p-state transitions. MSRs are 64-bit. For     */
 /* writes (wrmsr - opcode 0f 30), the register number is placed in ecx, and   */
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	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c	Wed May 12 20:27:23 2004
@@ -38,13 +38,37 @@
 #define dprintk(msg...) do { } while(0)
 #endif
 
+struct cpu_id
+{
+	__u8	x86;            /* CPU family */
+	__u8	x86_vendor;     /* CPU vendor */
+	__u8	x86_model;	/* model */
+	__u8	x86_mask;	/* stepping */
+};
+
+static const struct cpu_id cpu_id_banias = {
+	.x86_vendor = X86_VENDOR_INTEL,
+	.x86 = 6,
+	.x86_model = 9,
+	.x86_mask = 5,
+};
+
+static const struct cpu_id cpu_id_dothan_a1 = {
+	.x86_vendor = X86_VENDOR_INTEL,
+	.x86 = 6,
+	.x86_model = 13,
+	.x86_mask = 1,
+};
+
 struct cpu_model
 {
+	const struct cpu_id *cpu_id;
 	const char	*model_name;
 	unsigned	max_freq; /* max clock in kHz */
 
 	struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */
 };
+static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x);
 
 /* Operating points for current CPU */
 static struct cpu_model *centrino_model;
@@ -67,8 +91,8 @@
  * M.
  */
 
-/* Ultra Low Voltage Intel Pentium M processor 900MHz */
-static struct cpufreq_frequency_table op_900[] =
+/* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */
+static struct cpufreq_frequency_table banias_900[] =
 {
 	OP(600,  844),
 	OP(800,  988),
@@ -76,8 +100,8 @@
 	{ .frequency = CPUFREQ_TABLE_END }
 };
 
-/* Ultra Low Voltage Intel Pentium M processor 1000MHz */
-static struct cpufreq_frequency_table op_1000[] =
+/* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */
+static struct cpufreq_frequency_table banias_1000[] =
 {
 	OP(600,  844),
 	OP(800,  972),
@@ -86,8 +110,8 @@
 	{ .frequency = CPUFREQ_TABLE_END }
 };
 
-/* Low Voltage Intel Pentium M processor 1.10GHz */
-static struct cpufreq_frequency_table op_1100[] =
+/* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */
+static struct cpufreq_frequency_table banias_1100[] =
 {
 	OP( 600,  956),
 	OP( 800, 1020),
@@ -98,8 +122,8 @@
 };
 
 
-/* Low Voltage Intel Pentium M processor 1.20GHz */
-static struct cpufreq_frequency_table op_1200[] =
+/* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */
+static struct cpufreq_frequency_table banias_1200[] =
 {
 	OP( 600,  956),
 	OP( 800, 1004),
@@ -110,8 +134,8 @@
 	{ .frequency = CPUFREQ_TABLE_END }
 };
 
-/* Intel Pentium M processor 1.30GHz */
-static struct cpufreq_frequency_table op_1300[] = 
+/* Intel Pentium M processor 1.30GHz (Banias) */
+static struct cpufreq_frequency_table banias_1300[] = 
 {
 	OP( 600,  956),
 	OP( 800, 1260),
@@ -121,8 +145,8 @@
 	{ .frequency = CPUFREQ_TABLE_END }
 };
 
-/* Intel Pentium M processor 1.40GHz */
-static struct cpufreq_frequency_table op_1400[] = 
+/* Intel Pentium M processor 1.40GHz (Banias) */
+static struct cpufreq_frequency_table banias_1400[] = 
 {
 	OP( 600,  956),
 	OP( 800, 1180),
@@ -132,8 +156,8 @@
 	{ .frequency = CPUFREQ_TABLE_END }
 };
 
-/* Intel Pentium M processor 1.50GHz */
-static struct cpufreq_frequency_table op_1500[] = 
+/* Intel Pentium M processor 1.50GHz (Banias) */
+static struct cpufreq_frequency_table banias_1500[] = 
 {
 	OP( 600,  956),
 	OP( 800, 1116),
@@ -144,8 +168,8 @@
 	{ .frequency = CPUFREQ_TABLE_END }
 };
 
-/* Intel Pentium M processor 1.60GHz */
-static struct cpufreq_frequency_table op_1600[] = 
+/* Intel Pentium M processor 1.60GHz (Banias) */
+static struct cpufreq_frequency_table banias_1600[] = 
 {
 	OP( 600,  956),
 	OP( 800, 1036),
@@ -156,8 +180,8 @@
 	{ .frequency = CPUFREQ_TABLE_END }
 };
 
-/* Intel Pentium M processor 1.70GHz */
-static struct cpufreq_frequency_table op_1700[] =
+/* Intel Pentium M processor 1.70GHz (Banias) */
+static struct cpufreq_frequency_table banias_1700[] =
 {
 	OP( 600,  956),
 	OP( 800, 1004),
@@ -169,26 +193,31 @@
 };
 #undef OP
 
-#define _CPU(max, name)	\
-	{ "Intel(R) Pentium(R) M processor " name "MHz", (max)*1000, op_##max }
-#define CPU(max)	_CPU(max, #max)
+#define _BANIAS(cpuid, max, name)	\
+{	.cpu_id		= cpuid,	\
+	.model_name	= "Intel(R) Pentium(R) M processor " name "MHz", \
+	.max_freq	= (max)*1000,	\
+	.op_points	= banias_##max,	\
+}
+#define BANIAS(max)	_BANIAS(&cpu_id_banias, max, #max)
 
 /* CPU models, their operating frequency range, and freq/voltage
    operating points */
 static struct cpu_model models[] = 
 {
-       _CPU( 900, " 900"),
-	CPU(1000),
-	CPU(1100),
-	CPU(1200),
-	CPU(1300),
-	CPU(1400),
-	CPU(1500),
-	CPU(1600),
-	CPU(1700),
+	_BANIAS(&cpu_id_banias, 900, " 900"),
+	BANIAS(1000),
+	BANIAS(1100),
+	BANIAS(1200),
+	BANIAS(1300),
+	BANIAS(1400),
+	BANIAS(1500),
+	BANIAS(1600),
+	BANIAS(1700),
 	{ 0, }
 };
-#undef CPU
+#undef _BANIAS
+#undef BANIAS
 
 static int centrino_cpu_init_table(struct cpufreq_policy *policy)
 {
@@ -196,7 +225,8 @@
 	struct cpu_model *model;
 
 	for(model = models; model->model_name != NULL; model++)
-		if (strcmp(cpu->x86_model_id, model->model_name) == 0)
+		if ((strcmp(cpu->x86_model_id, model->model_name) == 0) &&
+		    (!centrino_verify_cpu_id(cpu, model->cpu_id)))
 			break;
 	if (model->model_name == NULL) {
 		printk(KERN_INFO PFX "no support for CPU model \"%s\": "
@@ -217,6 +247,16 @@
 static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; }
 #endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */
 
+static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x)
+{
+	if ((c->x86 == x->x86) &&
+	    (c->x86_vendor == x->x86_vendor) &&
+	    (c->x86_model == x->x86_model) &&
+	    (c->x86_mask == x->x86_mask))
+		return 0;
+	return -ENODEV;
+}
+
 /* Extract clock in kHz from PERF_CTL value */
 static unsigned extract_clock(unsigned msr)
 {
@@ -225,9 +265,11 @@
 }
 
 /* Return the current CPU frequency in kHz */
-static unsigned get_cur_freq(void)
+static unsigned int get_cur_freq(unsigned int cpu)
 {
 	unsigned l, h;
+	if (cpu)
+		return 0;
 
 	rdmsr(MSR_IA32_PERF_STATUS, l, h);
 	return extract_clock(l);
@@ -322,7 +364,7 @@
                 goto err_kfree;
         }
 
-	cur_freq = get_cur_freq();
+	cur_freq = get_cur_freq(0);
 
         for (i=0; i<p.state_count; i++) {
 		centrino_model->op_points[i].index = p.states[i].control;
@@ -357,13 +399,8 @@
 	if (!cpu_has(cpu, X86_FEATURE_EST))
 		return -ENODEV;
 
-	/* Only Intel Pentium M stepping 5 for now - add new CPUs as
-	   they appear after making sure they use PERF_CTL in the same
-	   way. */
-	if (cpu->x86_vendor != X86_VENDOR_INTEL ||
-	    cpu->x86        != 6 ||
-	    cpu->x86_model  != 9 ||
-	    cpu->x86_mask   != 5) {
+	if ((centrino_verify_cpu_id(cpu, &cpu_id_banias)) &&
+	    (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1))) {
 		printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
 		       "send /proc/cpuinfo to " MAINTAINER "\n");
 		return -ENODEV;
@@ -391,10 +428,10 @@
 		}
 	}
 
-	freq = get_cur_freq();
+	freq = get_cur_freq(0);
 
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-	policy->cpuinfo.transition_latency = 10; /* 10uS transition latency */
+	policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
 	policy->cur = freq;
 
 	dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n",
@@ -516,6 +553,7 @@
 	.exit		= centrino_cpu_exit,
 	.verify 	= centrino_verify,
 	.target 	= centrino_target,
+	.get		= get_cur_freq,
 	.attr           = centrino_attr,
 	.owner		= THIS_MODULE,
 };
diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c	Wed May 12 20:27:23 2004
@@ -322,6 +322,10 @@
 	return 0;
 }
 
+static unsigned int speedstep_get(unsigned int cpu)
+{
+	return speedstep_get_processor_frequency(speedstep_processor);
+}
 
 static struct freq_attr* speedstep_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
@@ -335,6 +339,7 @@
 	.target 	= speedstep_target,
 	.init		= speedstep_cpu_init,
 	.exit		= speedstep_cpu_exit,
+	.get		= speedstep_get,
 	.owner		= THIS_MODULE,
 	.attr		= speedstep_attr,
 };
diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c	Wed May 12 20:27:23 2004
@@ -36,6 +36,8 @@
 static int		smi_cmd		= 0;
 static unsigned int	smi_sig		= 0;
 
+/* info about the processor */
+static unsigned int	speedstep_processor = 0;
 
 /* 
  *   There are only two frequency states for each processor. Values
@@ -258,10 +260,11 @@
 				&speedstep_freqs[SPEEDSTEP_HIGH].frequency);
 	if (result) {
 		/* fall back to speedstep_lib.c dection mechanism: try both states out */
-		unsigned int speedstep_processor = speedstep_detect_processor();
-
 		dprintk(KERN_INFO PFX "could not detect low and high frequencies by SMI call.\n");
 		if (!speedstep_processor)
+			speedstep_processor = speedstep_detect_processor();
+
+		if (!speedstep_processor)
 			return -ENODEV;
 
 		result = speedstep_get_freqs(speedstep_processor,
@@ -298,13 +301,23 @@
 	return 0;
 }
 
-
 static int speedstep_cpu_exit(struct cpufreq_policy *policy)
 {
 	cpufreq_frequency_table_put_attr(policy->cpu);
 	return 0;
 }
 
+static unsigned int speedstep_get(unsigned int cpu)
+{
+	if (cpu)
+		return -ENODEV;
+	if (!speedstep_processor)
+		speedstep_processor = speedstep_detect_processor();
+	if (!speedstep_processor)
+		return 0;
+	return speedstep_get_processor_frequency(speedstep_processor);
+}
+
 
 static int speedstep_resume(struct cpufreq_policy *policy)
 {
@@ -327,6 +340,7 @@
 	.target 	= speedstep_target,
 	.init		= speedstep_cpu_init,
 	.exit		= speedstep_cpu_exit,
+	.get		= speedstep_get,
 	.resume		= speedstep_resume,
 	.owner		= THIS_MODULE,
 	.attr		= speedstep_attr,
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
--- a/arch/i386/kernel/timers/timer_tsc.c	Wed May 12 20:27:23 2004
+++ b/arch/i386/kernel/timers/timer_tsc.c	Wed May 12 20:27:23 2004
@@ -27,6 +27,8 @@
 struct timer_opts timer_tsc;
 #endif
 
+static inline void cpufreq_delayed_get(void);
+
 int tsc_disable __initdata = 0;
 
 extern spinlock_t i8253_lock;
@@ -241,6 +243,9 @@
 
 			clock_fallback();
 		}
+		/* ... but give the TSC a fair chance */
+		if (lost_count > 25)
+			cpufreq_delayed_get();
 	} else
 		lost_count = 0;
 	/* update the monotonic base value */
@@ -324,15 +329,40 @@
 
 
 #ifdef CONFIG_CPU_FREQ
+#include <linux/workqueue.h>
+
+static unsigned int cpufreq_delayed_issched = 0;
+static unsigned int cpufreq_init = 0;
+static struct work_struct cpufreq_delayed_get_work;
+
+static void handle_cpufreq_delayed_get(void *v)
+{
+	unsigned int cpu;
+	for_each_online_cpu(cpu) {
+		cpufreq_get(cpu);
+	}
+	cpufreq_delayed_issched = 0;
+}
+
+/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries
+ * to verify the CPU frequency the timing core thinks the CPU is running
+ * at is still correct.
+ */
+static inline void cpufreq_delayed_get(void) 
+{
+	if (cpufreq_init && !cpufreq_delayed_issched) {
+		cpufreq_delayed_issched = 1;
+		printk(KERN_DEBUG "Losing some ticks... checking if CPU frequency changed.\n");
+		schedule_work(&cpufreq_delayed_get_work);
+	}
+}
+
 /* If the CPU frequency is scaled, TSC-based delays will need a different
- * loops_per_jiffy value to function properly. An exception to this
- * are modern Intel Pentium 4 processors, where the TSC runs at a constant
- * speed independent of frequency scaling. 
+ * loops_per_jiffy value to function properly.
  */
 
 static unsigned int  ref_freq = 0;
 static unsigned long loops_per_jiffy_ref = 0;
-static unsigned int  variable_tsc = 1;
 
 #ifndef CONFIG_SMP
 static unsigned long fast_gettimeoffset_ref = 0;
@@ -356,14 +386,15 @@
 	}
 
 	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
-		if (variable_tsc)
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+	    (val == CPUFREQ_RESUMECHANGE)) {
+		if (!freq->flags & CPUFREQ_CONST_LOOPS)
 			cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
 #ifndef CONFIG_SMP
 		if (cpu_khz)
 			cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
 		if (use_tsc) {
-			if (variable_tsc) {
+			if (!freq->flags & CPUFREQ_CONST_LOOPS) {
 				fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
 				set_cyc2ns_scale(cpu_khz/1000);
 			}
@@ -382,14 +413,17 @@
 
 static int __init cpufreq_tsc(void)
 {
-	/* P4 and above CPU TSC freq doesn't change when CPU frequency changes*/
-	if ((boot_cpu_data.x86 >= 15) && (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL))
-		variable_tsc = 0;
-
-	return cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+	int ret;
+	INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);
+	ret = cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+	if (!ret)
+		cpufreq_init = 1;
+	return ret;
 }
 core_initcall(cpufreq_tsc);
 
+#else /* CONFIG_CPU_FREQ */
+static inline void cpufreq_delayed_get(void) { return; }
 #endif 
 
 
diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
--- a/arch/sparc64/kernel/time.c	Wed May 12 20:27:23 2004
+++ b/arch/sparc64/kernel/time.c	Wed May 12 20:27:23 2004
@@ -1035,7 +1035,8 @@
 		ft->clock_tick_ref = cpu_data(cpu).clock_tick;
 	}
 	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+	    (val == CPUFREQ_RESUMECHANGE)) {
 		cpu_data(cpu).udelay_val =
 			cpufreq_scale(ft->udelay_val_ref,
 				      ft->ref_freq,
diff -Nru a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
--- a/arch/x86_64/kernel/time.c	Wed May 12 20:27:23 2004
+++ b/arch/x86_64/kernel/time.c	Wed May 12 20:27:23 2004
@@ -532,7 +532,8 @@
 		cpu_khz_ref = cpu_khz;
 	}
         if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-            (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
+            (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+	    (val == CPUFREQ_RESUMECHANGE)) {
                 *lpj =
 		cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
 
diff -Nru a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
--- a/drivers/char/sh-sci.c	Wed May 12 20:27:23 2004
+++ b/drivers/char/sh-sci.c	Wed May 12 20:27:23 2004
@@ -1239,7 +1239,8 @@
 	struct cpufreq_freqs *freqs = p;
 	int i;
 
-	if (phase == CPUFREQ_POSTCHANGE) {
+	if ((phase == CPUFREQ_POSTCHANGE) ||
+	    (phase == CPUFREQ_RESUMECHANGE)) {
 		for (i = 0; i < SCI_NPORTS; i++) {
 			/*
 			 * This will force a baud rate change in hardware.
diff -Nru a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
--- a/drivers/cpufreq/cpufreq.c	Wed May 12 20:27:23 2004
+++ b/drivers/cpufreq/cpufreq.c	Wed May 12 20:27:23 2004
@@ -33,9 +33,10 @@
 static struct cpufreq_policy	*cpufreq_cpu_data[NR_CPUS];
 static spinlock_t		cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
 
-/* internal prototype */
+/* internal prototypes */
 static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
-
+static void handle_update(void *data);
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci);
 
 /**
  * Two notifier lists: the "policy" list is involved in the 
@@ -161,6 +162,7 @@
 show_one(cpuinfo_max_freq, cpuinfo.max_freq);
 show_one(scaling_min_freq, min);
 show_one(scaling_max_freq, max);
+show_one(scaling_cur_freq, cur);
 
 /**
  * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access
@@ -189,6 +191,18 @@
 store_one(scaling_max_freq,max);
 
 /**
+ * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
+ */
+static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, char *buf)
+{
+	unsigned int cur_freq = cpufreq_get(policy->cpu);
+	if (!cur_freq)
+		return sprintf(buf, "<unknown>");
+	return sprintf(buf, "%u\n", cur_freq);
+}
+
+
+/**
  * show_scaling_governor - show the current policy for the specified CPU
  */
 static ssize_t show_scaling_governor (struct cpufreq_policy * policy, char *buf)
@@ -268,6 +282,12 @@
 	.show = show_##_name, \
 }
 
+#define define_one_ro0400(_name) \
+struct freq_attr _name = { \
+	.attr = { .name = __stringify(_name), .mode = 0400 }, \
+	.show = show_##_name, \
+}
+
 #define define_one_rw(_name) \
 struct freq_attr _name = { \
 	.attr = { .name = __stringify(_name), .mode = 0644 }, \
@@ -275,10 +295,12 @@
 	.store = store_##_name, \
 }
 
+define_one_ro0400(cpuinfo_cur_freq);
 define_one_ro(cpuinfo_min_freq);
 define_one_ro(cpuinfo_max_freq);
 define_one_ro(scaling_available_governors);
 define_one_ro(scaling_driver);
+define_one_ro(scaling_cur_freq);
 define_one_rw(scaling_min_freq);
 define_one_rw(scaling_max_freq);
 define_one_rw(scaling_governor);
@@ -369,6 +391,7 @@
 	policy->cpu = cpu;
 	init_MUTEX_LOCKED(&policy->lock);
 	init_completion(&policy->kobj_unregister);
+	INIT_WORK(&policy->update, handle_update, (void *)(long)cpu);
 
 	/* call driver. From then on the cpufreq must be able
 	 * to accept all calls to ->verify and ->setpolicy for this CPU
@@ -394,6 +417,10 @@
 		sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
 		drv_attr++;
 	}
+	if (cpufreq_driver->get)
+		sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
+	if (cpufreq_driver->target)
+		sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
 
 	spin_lock_irqsave(&cpufreq_driver_lock, flags);
 	cpufreq_cpu_data[cpu] = policy;
@@ -474,11 +501,86 @@
 	return 0;
 }
 
+
+static void handle_update(void *data)
+{
+	unsigned int cpu = (unsigned int)(long)data;
+	cpufreq_update_policy(cpu);
+}
+
+/**
+ *	cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble.
+ *	@cpu: cpu number
+ *	@old_freq: CPU frequency the kernel thinks the CPU runs at
+ *	@new_freq: CPU frequency the CPU actually runs at
+ *
+ *	We adjust to current frequency first, and need to clean up later. So either call
+ *	to cpufreq_update_policy() or schedule handle_update()).
+ */
+static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigned int new_freq)
+{
+	struct cpufreq_freqs freqs;
+
+	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", old_freq, new_freq);
+
+	freqs.cpu = cpu;
+	freqs.old = old_freq;
+	freqs.new = new_freq;
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+}
+
+
+/** 
+ * cpufreq_get - get the current CPU frequency (in kHz)
+ * @cpu: CPU number
+ *
+ * Get the CPU current (static) CPU frequency
+ */
+unsigned int cpufreq_get(unsigned int cpu)
+{
+	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+	unsigned int ret = 0;
+
+	if (!policy)
+		return 0;
+
+	if (!cpufreq_driver->get)
+		goto out;
+
+	down(&policy->lock);
+
+	ret = cpufreq_driver->get(cpu);
+
+	if (ret && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) 
+	{
+		/* verify no discrepancy between actual and saved value exists */
+		if (unlikely(ret != policy->cur)) {
+			cpufreq_out_of_sync(cpu, policy->cur, ret);
+			schedule_work(&policy->update);
+		}
+	}
+
+	up(&policy->lock);
+
+ out:
+	cpufreq_cpu_put(policy);
+
+	return (ret);
+}
+EXPORT_SYMBOL(cpufreq_get);
+
+
 /**
- *	cpufreq_resume - restore the CPU clock frequency after resume
+ *	cpufreq_resume -  restore proper CPU frequency handling after resume
  *
- *	Restore the CPU clock frequency so that our idea of the current
- *	frequency reflects the actual hardware.
+ *	1.) resume CPUfreq hardware support (cpufreq_driver->resume())
+ *	2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync
+ *	3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored.
  */
 static int cpufreq_resume(struct sys_device * sysdev)
 {
@@ -498,25 +600,37 @@
 	if (!cpu_policy)
 		return -EINVAL;
 
-	if (cpufreq_driver->resume)
-		ret = cpufreq_driver->resume(cpu_policy);
-	if (ret) {
-		printk(KERN_ERR "cpufreq: resume failed in ->resume step on CPU %u\n", cpu_policy->cpu);
-		goto out;
-	}
+	if (!cpufreq_driver->flags & CPUFREQ_CONST_LOOPS) {
+		unsigned int cur_freq = 0;
 
-	if (cpufreq_driver->setpolicy)
-		ret = cpufreq_driver->setpolicy(cpu_policy);
-	else
-		/* CPUFREQ_RELATION_H or CPUFREQ_RELATION_L have the same effect here, as cpu_policy->cur is known
-		 * to be a valid and exact target frequency
-		 */
-		ret = cpufreq_driver->target(cpu_policy, cpu_policy->cur, CPUFREQ_RELATION_H);
+		if (cpufreq_driver->get)
+			cur_freq = cpufreq_driver->get(cpu_policy->cpu);
 
-	if (ret)
-		printk(KERN_ERR "cpufreq: resume failed in ->setpolicy/target step on CPU %u\n", cpu_policy->cpu);
+		if (!cur_freq || !cpu_policy->cur) {
+			printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n");
+			goto out;
+		}
+
+		if (unlikely(cur_freq != cpu_policy->cur)) {
+			struct cpufreq_freqs freqs;
+
+			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);
+
+			freqs.cpu = cpu;
+			freqs.old = cpu_policy->cur;
+			freqs.new = cur_freq;
+
+			notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs);
+			adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
+		}
+	}
 
 out:
+	schedule_work(&cpu_policy->update);
 	cpufreq_cpu_put(cpu_policy);
 	return ret;
 }
@@ -904,16 +1018,20 @@
 
 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_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
-#define adjust_jiffies(x...) do {} while (0)
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
 #endif
 
 
@@ -925,13 +1043,29 @@
  */
 void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
 {
-	if (irqs_disabled())
-		return;   /* Only valid if we're in the resume process where
-			   * everyone knows what CPU frequency we are at */
+	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;
@@ -969,6 +1103,9 @@
 	if (!driver_data || !driver_data->verify || !driver_data->init ||
 	    ((!driver_data->setpolicy) && (!driver_data->target)))
 		return -EINVAL;
+
+	if (driver_data->setpolicy)
+		driver_data->flags |= CPUFREQ_CONST_LOOPS;
 
 	spin_lock_irqsave(&cpufreq_driver_lock, flags);
 	if (cpufreq_driver) {
diff -Nru a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
--- a/drivers/cpufreq/cpufreq_userspace.c	Wed May 12 20:27:23 2004
+++ b/drivers/cpufreq/cpufreq_userspace.c	Wed May 12 20:27:23 2004
@@ -145,19 +145,6 @@
 EXPORT_SYMBOL_GPL(cpufreq_setmax);
 
 
-/** 
- * cpufreq_get - get the current CPU frequency (in kHz)
- * @cpu: CPU number
- *
- * Get the CPU current (static) CPU frequency
- */
-unsigned int cpufreq_get(unsigned int cpu)
-{
-	return cpu_cur_freq[cpu];
-}
-EXPORT_SYMBOL(cpufreq_get);
-
-
 #ifdef CONFIG_CPU_FREQ_24_API
 
 
@@ -542,20 +529,6 @@
 	return 0;
 }
 
-/* on ARM SA1100 we need to rely on the values of cpufreq_get() - because 
- * of this, cpu_cur_freq[] needs to be set early.
- */
-#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_SA1100)
-extern unsigned int sa11x0_getspeed(void);
-
-static void cpufreq_sa11x0_compat(void)
-{
-	cpu_cur_freq[0] = sa11x0_getspeed();
-}
-#else
-#define cpufreq_sa11x0_compat() do {} while(0)
-#endif
-
 
 struct cpufreq_governor cpufreq_gov_userspace = {
 	.name		= "userspace",
@@ -564,21 +537,12 @@
 };
 EXPORT_SYMBOL(cpufreq_gov_userspace);
 
-static int already_init = 0;
-
-int cpufreq_gov_userspace_init(void)
+static int __init cpufreq_gov_userspace_init(void)
 {
-	if (!already_init) {
-		down(&userspace_sem);
-		cpufreq_sa11x0_compat();
-		cpufreq_sysctl_init();
-		cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
-		already_init = 1;
-		up(&userspace_sem);
-	}
+	cpufreq_sysctl_init();
+	cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
 	return cpufreq_register_governor(&cpufreq_gov_userspace);
 }
-EXPORT_SYMBOL(cpufreq_gov_userspace_init);
 
 
 static void __exit cpufreq_gov_userspace_exit(void)
diff -Nru a/drivers/pcmcia/sa11xx_core.c b/drivers/pcmcia/sa11xx_core.c
--- a/drivers/pcmcia/sa11xx_core.c	Wed May 12 20:27:23 2004
+++ b/drivers/pcmcia/sa11xx_core.c	Wed May 12 20:27:23 2004
@@ -933,6 +933,8 @@
 		if (freqs->new < freqs->old)
 			sa1100_pcmcia_update_mecr(freqs->new);
 		break;
+	case CPUFREQ_RESUMECHANGE:
+		sa1100_pcmcia_update_mecr(freqs->new);
 	}
 
 	return 0;
diff -Nru a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
--- a/drivers/serial/sh-sci.c	Wed May 12 20:27:23 2004
+++ b/drivers/serial/sh-sci.c	Wed May 12 20:27:23 2004
@@ -758,7 +758,8 @@
 	struct cpufreq_freqs *freqs = p;
 	int i;
 
-	if (phase == CPUFREQ_POSTCHANGE) {
+	if ((phase == CPUFREQ_POSTCHANGE) ||
+	    (phase == CPUFREQ_RESUMECHANGE)){
 		for (i = 0; i < SCI_NPORTS; i++) {
 			struct uart_port *port = &sci_ports[i];
 
diff -Nru a/include/linux/cpufreq.h b/include/linux/cpufreq.h
--- a/include/linux/cpufreq.h	Wed May 12 20:27:23 2004
+++ b/include/linux/cpufreq.h	Wed May 12 20:27:23 2004
@@ -21,6 +21,7 @@
 #include <linux/kobject.h>
 #include <linux/sysfs.h>
 #include <linux/completion.h>
+#include <linux/workqueue.h>
 
 #define CPUFREQ_NAME_LEN 16
 
@@ -81,6 +82,9 @@
  	struct semaphore	lock;   /* CPU ->setpolicy or ->target may
 					   only be called once a time */
 
+	struct work_struct	update; /* if update_policy() needs to be
+					 * called, but you're in IRQ context */
+
 	struct cpufreq_real_policy	user_policy;
 
 	struct kobject		kobj;
@@ -96,11 +100,13 @@
 
 #define CPUFREQ_PRECHANGE	(0)
 #define CPUFREQ_POSTCHANGE	(1)
+#define CPUFREQ_RESUMECHANGE	(8)
 
 struct cpufreq_freqs {
 	unsigned int cpu;	/* cpu nr */
 	unsigned int old;
 	unsigned int new;
+	u8 flags;		/* flags of cpufreq_driver, see below. */
 };
 
 
@@ -187,6 +193,9 @@
 				 unsigned int target_freq,
 				 unsigned int relation);
 
+	/* should be defined, if possible */
+	unsigned int	(*get)	(unsigned int cpu);
+
 	/* optional */
 	int	(*exit)		(struct cpufreq_policy *policy);
 	int	(*resume)	(struct cpufreq_policy *policy);
@@ -195,8 +204,19 @@
 
 /* flags */
 
-#define CPUFREQ_STICKY	0x01	/* the driver isn't removed even if 
-				   all ->init() calls failed */
+#define CPUFREQ_STICKY		0x01	/* the driver isn't removed even if 
+					 * all ->init() calls failed */
+#define CPUFREQ_CONST_LOOPS 	0x02	/* loops_per_jiffy or other kernel
+					 * "constants" aren't affected by
+					 * frequency transitions */
+#define CPUFREQ_PANIC_OUTOFSYNC	0x04	/* panic if cpufreq's opinion of
+					 * current frequency differs from
+					 * actual frequency */
+#define CPUFREQ_PANIC_RESUME_OUTOFSYNC 0x08 /* panic if cpufreq's opinion of
+					 * current frequency differs from
+					 * actual frequency on resume
+					 * from sleep. */
+
 
 int cpufreq_register_driver(struct cpufreq_driver *driver_data);
 int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
@@ -234,6 +254,9 @@
 int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
 int cpufreq_update_policy(unsigned int cpu);
 
+/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
+unsigned int cpufreq_get(unsigned int cpu);
+
 /* the proc_intf.c needs this */
 int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor);
 
@@ -241,13 +264,10 @@
 /*********************************************************************
  *                      CPUFREQ USERSPACE GOVERNOR                   *
  *********************************************************************/
-int cpufreq_gov_userspace_init(void);
-
 #ifdef CONFIG_CPU_FREQ_24_API
 
 int cpufreq_setmax(unsigned int cpu);
 int cpufreq_set(unsigned int kHz, unsigned int cpu);
-unsigned int cpufreq_get(unsigned int cpu);
 
 
 /* /proc/sys/cpu */
