bk://linux-dj.bkbits.net/cpufreq davej@redhat.com|ChangeSet|20040507145144|60129 davej # This is a BitKeeper generated diff -Nru style patch. # # 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 Sun May 9 21:11:56 2004 +++ b/Documentation/cpu-freq/core.txt Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/arm/mach-integrator/cpu.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/arm/mach-sa1100/cpu-sa1100.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/arm/mach-sa1100/cpu-sa1110.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/arm/mach-sa1100/generic.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/arm/mach-sa1100/generic.h Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/elanfreq.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c Sun May 9 21:11:56 2004 @@ -380,6 +380,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; @@ -472,6 +479,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/longrun.c b/arch/i386/kernel/cpu/cpufreq/longrun.c --- a/arch/i386/kernel/cpu/cpufreq/longrun.c Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/longrun.c Sun May 9 21:11:56 2004 @@ -128,6 +128,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 +261,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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c Sun May 9 21:11:56 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) { @@ -180,7 +181,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 " @@ -188,11 +189,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 \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 " @@ -252,6 +269,43 @@ return 0; } +static unsigned int cpufreq_p4_get(unsigned int cpu) +{ + unsigned int hyperthreading; + cpumask_t cpus_allowed, affected_cpu_map; + u32 l, h; + + hyperthreading = 0; + + /* only run on CPU to be set, or on its sibling */ + cpus_allowed = current->cpus_allowed; + affected_cpu_map = cpumask_of_cpu(cpu); +#ifdef CONFIG_X86_HT + hyperthreading = ((cpu_has_ht) && (smp_num_siblings == 2)); + if (hyperthreading) { + sibling = cpu_sibling_map[cpu]; + cpu_set(sibling, affected_cpu_map); + } +#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, @@ -262,6 +316,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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c Sun May 9 21:11:56 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; iop_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,7 +428,7 @@ } } - freq = get_cur_freq(); + freq = get_cur_freq(0); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 10; /* 10uS transition latency */ @@ -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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/i386/kernel/timers/timer_tsc.c Sun May 9 21:11:56 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 == 50) + cpufreq_delayed_get(); } else lost_count = 0; /* update the monotonic base value */ @@ -324,15 +329,35 @@ #ifdef CONFIG_CPU_FREQ +#include + +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); + } +} + +/* 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) + 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 +381,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 +408,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 Sun May 9 21:11:56 2004 +++ b/arch/sparc64/kernel/time.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/arch/x86_64/kernel/time.c Sun May 9 21:11:56 2004 @@ -531,7 +531,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 Sun May 9 21:11:56 2004 +++ b/drivers/char/sh-sci.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/drivers/cpufreq/cpufreq.c Sun May 9 21:11:56 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, ""); + 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 *) 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) 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 Sun May 9 21:11:56 2004 +++ b/drivers/cpufreq/cpufreq_userspace.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/drivers/pcmcia/sa11xx_core.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/drivers/serial/sh-sci.c Sun May 9 21:11:56 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 Sun May 9 21:11:56 2004 +++ b/include/linux/cpufreq.h Sun May 9 21:11:56 2004 @@ -21,6 +21,7 @@ #include #include #include +#include #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 */